pcb-4.2.2/0000775000076400007640000000000013611113557007301 500000000000000pcb-4.2.2/configure.ac0000664000076400007640000011721313610151301011500 00000000000000dnl Process this file with autoconf to produce a configure script. AC_INIT([pcb], [4.2.2]) AC_CONFIG_SRCDIR([src/draw.c]) AC_PREREQ([2.69]) AM_INIT_AUTOMAKE([1.9]) AC_GNU_SOURCE AC_CONFIG_HEADERS([config.h]) ########################################################################## # # Try to figure out if we are building from git sources. # If we are then unless building of the documentation has # been disabled then just require the user have all the right # tools. Users building from a tarball won't need latex, makeinfo, # etc. but if you're already downloading development sources, then # it is not unreasonable to require development tools. What motivated # this is that using maintainer mode proved to cause regular confusion. pcb_sources="tarball" AC_MSG_CHECKING([if you are building from a git checkout]) pcb_git_version=no if test -f $srcdir/.gitignore ; then pcb_git_version=yes AC_MSG_RESULT([yes]) pcb_sources="GIT" else AC_MSG_RESULT([no]) fi AM_CONDITIONAL(GIT_VERSION, test x$pcb_git_version = xyes) AC_MSG_CHECKING([if you are building from a anoncvs checkout]) pcb_cvs_version=no if test -f $srcdir/CVS/Root ; then pcb_cvs_version=yes AC_MSG_RESULT([yes]) pcb_sources="CVS" else AC_MSG_RESULT([no]) fi AM_CONDITIONAL(CVS_VERSION, test x$pcb_cvs_version = xyes) AM_CONDITIONAL(GIT_OR_CVS_VERSION, test x$pcb_git_version = xyes -o x$pcb_cvs_version = xyes) ########################################################################## # # See if we are supposed to build the docs # docs_yesno=yes AC_MSG_CHECKING([if the documentation should be built]) AC_ARG_ENABLE([doc], [ --enable-doc Build and install the documentation [[default=yes]]], [ if test "X$enable_doc" = "Xno" ; then DOC="" AC_MSG_RESULT([no]) docs_yesno=no else DOC=doc AC_MSG_RESULT([yes]) docs_yesno=yes fi ], [ DOC=doc AC_MSG_RESULT([yes]) docs_yesno=yes ]) AC_SUBST(DOC) dnl determine host type AC_CANONICAL_HOST AC_MSG_CHECKING(for windows) PCB_PATH_DELIMETER=":" PCB_DIR_SEPARATOR_S="/" PCB_DIR_SEPARATOR_C='/' case $host in *-*-mingw* ) WIN32=yes CFLAGS="$CFLAGS ${MINGW_CFLAGS:--mms-bitfields -mwindows}" CPPFLAGS="$CPPFLAGS ${MINGW_CPPFLAGS}" ;; * ) WIN32=no ;; esac AC_MSG_RESULT($WIN32) AC_SUBST(WIN32) AM_CONDITIONAL(WIN32, test x$WIN32 = xyes) if test "x$WIN32" = "xyes" ; then PCB_PATH_DELIMETER=";" PCB_DIR_SEPARATOR_S="\\\\" PCB_DIR_SEPARATOR_C='\\' fi AC_DEFINE_UNQUOTED(PCB_DIR_SEPARATOR_C,'$PCB_DIR_SEPARATOR_C',[Directory separator char]) AC_DEFINE_UNQUOTED(PCB_DIR_SEPARATOR_S,"$PCB_DIR_SEPARATOR_S",[Directory separator string]) AC_DEFINE_UNQUOTED(PCB_PATH_DELIMETER,"$PCB_PATH_DELIMETER",[Search path separator string]) dnl Checks for programs. AC_PROG_CC AC_PROG_CXX if test "x$WIN32" = "xyes" ; then AC_CHECK_TOOL(WINDRES, windres, [no]) if test "$WINDRES" = "no" ; then AC_MSG_ERROR([*** Could not find an implementation of windres in your PATH.]) fi fi # i18n GETTEXT_PACKAGE=$PACKAGE AH_TEMPLATE([GETTEXT_PACKAGE], [Name of this program's gettext domain]) AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"]) AC_SUBST(GETTEXT_PACKAGE) AM_GNU_GETTEXT_VERSION([0.19.3]) AM_GNU_GETTEXT AC_MSG_CHECKING([if $MSGFMT understands msgctxt (message context)]) cat > conftest.po </dev/null; exit) 2>&AS_MESSAGE_LOG_FD then dnl AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) AC_MSG_ERROR([It appears that your gettext tools ($MSGFMT) is too old. You should install a newer gettext tools (>= 0.19.3 suggested). You may specify the location of the msgfmt executible with MSGFMT=/path/to/msgfmt on the configure command line. ]) fi rm -f conftest.po conftest.gmo IT_PROG_INTLTOOL([0.35.0]) AC_C_INLINE AC_PROG_CC_STDC AC_PROG_CC_C99 AM_PROG_CC_C_O AC_PROG_CPP AC_MSG_CHECKING([that C compiler supports C99]) if test "X$ac_cv_prog_cc_c99" = "Xno"; then AC_MSG_RESULT([no]) AC_MSG_ERROR([A C99-compliant compiler is requred]) else AC_MSG_RESULT([yes]) fi AC_PROG_AWK AC_PROG_MKDIR_P AM_PROG_LEX AC_PATH_PROG(LEX_PATH, $LEX, [notfound]) if test "$LEX_PATH" = "notfound" ; then AC_MSG_ERROR([Couldn't find a usable lex program. Please install flex which is available from ftp://ftp.gnu.org/pub/non-gnu/flex/ ]) fi AC_PROG_YACC AC_PATH_PROG(YACC_PATH, $YACC, [notfound]) if test "$YACC_PATH" = "notfound" ; then AC_MSG_ERROR([Couldn't find a usable yacc program. Please install bison which is available from ftp://ftp.gnu.org/pub/gnu/bison/ ]) fi AC_PROG_INSTALL AC_PROG_RANLIB # # Used for building the icons # AC_PATH_PROG(XPMTOPPM, xpmtoppm, notfound) AC_PATH_PROG(PPMTOWINICON, ppmtowinicon, notfound) AC_PATH_PROG(CONVERT, convert, notfound) ########################################################################## # # if test "X$docs_yesno" = "Xyes" -a "X$pcb_git_version" = "Xyes" ; then AC_PATH_PROG(MKINFO, makeinfo, no) if test "X$MKINFO" != "Xno"; then AC_MSG_CHECKING([for GNU makeinfo version >= 4.6]) v=`$MKINFO --version | grep "GNU texinfo"` if test $? -ne 0; then AC_MSG_RESULT([non-GNU]) MKINFO="no" fi fi if test "X$MKINFO" != "Xno"; then vmajor=`echo "$v" | sed 's/.* \([[0-9]]*\)\.\([[0-9]]*\)$/\1/'` vminor=`echo "$v" | sed 's/.* \([[0-9]]*\)\.\([[0-9]]*\)$/\2/'` AC_MSG_RESULT([$vmajor.$vminor]) if test "$vmajor" -lt 4 \ || (test "$vmajor" -eq 4 && test "$vminor" -lt 6); then MKINFO=no fi fi if test "X$MKINFO" = "Xno"; then AC_MSG_ERROR([You have requested a build of the documentation. For this to work, you must have version 4.6 or newer of the GNU texinfo package. You seem to have $v Please update to a newer version of texinfo or disable building of the documentation with --disable-doc ]) fi AC_PATH_PROG(TEXI2DVI, texi2dvi, no) if test "X$TEXI2DVI" = "Xno"; then AC_MSG_ERROR([You have requested a build of the documentation. For this to work, you must have the texi2dvi program installed. Alternatively, you can disable building the documentation with --disable-doc.]) fi AC_PATH_PROG(PERL, perl, notfound) if test "X$PERL" = "Xnotfound"; then AC_MSG_ERROR([You have requested a build of the documentation. For this to work, you must have perl installed. Alternatively, you can disable building the documentation with --disable-doc. ]) fi AC_PATH_PROG([KPSEWHICH], [kpsewhich], [no]) if test "X$KPSEWHICH" = "Xno"; then AC_MSG_ERROR([You have requested a build of the documentation. For this to work, you must have a functional install of TeX and LaTeX. kpsewhich is part of TeX. Alternatively, you can disable building the documentation with --disable-doc.]) fi AC_MSG_CHECKING([If your TeX installation contains epsf.tex]) f=`$KPSEWHICH epsf.tex` if test $? -eq 0 ; then AC_MSG_RESULT([yes ($f)]) else AC_MSG_RESULT([no]) AC_MSG_ERROR([You have requested a build of the documentation. For this to work, you must have a functional install of TeX and LaTeX that includes epsf.tex. On some linux distributions this is part of the texlive-generic-recommended package. On NetBSD this is is part of the tex-epsf package. Alternatively, you can disable building the documentation with --disable-doc.]) fi fi ########################################################################## # # # FIXME: for now, only try to add -rdynamic if we're using gcc. We really # need to figure out what the correct test is here. In the mean time, this # should let things build with SunPRO again. if test "x$GCC" = "xyes"; then AC_MSG_CHECKING([If the compiler accepts -rdynamic]) old_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -rdynamic" AC_LINK_IFELSE([AC_LANG_PROGRAM()], [AC_MSG_RESULT([yes])], [LDFLAGS="$old_LDFLAGS" AC_MSG_RESULT([no]) ]) fi # ------------- HID config ------------------- hid_guis="" hid_printers="" hid_exporters="" hid_always="" for hid in `cd $srcdir/src/hid; echo *`; do F=$srcdir/src/hid/$hid/hid.conf if test -f $F then echo checking $F . $F case $type in gui ) hid_guis="$hid_guis $hid" ;; printer ) hid_printers="$hid_printers $hid" ;; export ) hid_exporters="$hid_exporters $hid" ;; always ) hid_always="$hid_always $hid" ;; esac fi done AC_MSG_CHECKING([for which gui to use]) AC_ARG_WITH([gui], [ --with-gui= Specify the GUI to use: batch gtk lesstif [[default=gtk]]], [], [with_gui=gtk] ) AC_MSG_RESULT([$with_gui]) case " $hid_guis no none " in *\ $with_gui\ * ) HIDLIST="$with_gui" ;; * ) AC_MSG_ERROR([$with_gui is not a valid gui]) ;; esac WITHGUI="$with_gui" AC_SUBST(WITHGUI) if test x"$with_gui" = x"none" -o x"$with_gui" = x"no" then HIDLIST= fi AC_MSG_CHECKING([whether to enable toporouter]) AC_ARG_ENABLE([toporouter], [AS_HELP_STRING([--enable-toporouter], [build toporouter [default=yes]]) ] ) AS_CASE(["x$enable_toporouter"],[xyes | xno],, [enable_toporouter=yes ] ) AC_MSG_RESULT([$enable_toporouter]) AM_CONDITIONAL([WITH_TOPOROUTER], test $enable_toporouter != no) AC_MSG_CHECKING([whether to enable toporouter output]) AC_ARG_ENABLE([toporouter-output], [AS_HELP_STRING([--enable-toporouter-output], [enable toporouter graphical output [default=no]]) ] ) AS_CASE(["z$enable_toporouter_output"],[zyes | zno],, [enable_toporouter_output=no] ) AC_MSG_RESULT([$enable_toporouter_output]) AS_CASE([$enable_toporouter_output],[yes], [ topo_output_enabled=1 ], [ topo_output_enabled=0 ] ) AC_DEFINE_UNQUOTED([TOPO_OUTPUT_ENABLED], [$topo_output_enabled], [Define to 1 to enable toporouter graphical output] ) PKG_PROG_PKG_CONFIG() if test "x$enable_toporouter_output" = "xyes"; then PKG_CHECK_MODULES(CAIRO, cairo,, [AC_MSG_ERROR([Cannot find cairo, needed by the toporouter Please review the following errors: $CAIRO_PKG_ERRORS])] ) fi AC_MSG_CHECKING([for whether to use DBUS]) AC_ARG_ENABLE([dbus], [ --enable-dbus Enable DBUS IPC], [],[ case " $with_gui " in *\ gtk\ *) enable_dbus=yes ;; *\ lesstif\ *) enable_dbus=yes ;; * ) enable_dbus=no ;; esac ]) AC_MSG_RESULT([$enable_dbus]) AM_CONDITIONAL(WITH_DBUS, test x$enable_dbus = xyes) if test "x$enable_dbus" = "xyes"; then case " $with_gui " in *\ gtk\ *) ;; *\ lesstif\ *) ;; * ) AC_MSG_ERROR([DBUS enabled but only works with a mainloop capable GUI HID. Either do not use --enable-dbus or enable the gtk or lesstif GUI HID.]) esac PKG_CHECK_MODULES(DBUS, dbus-1 >= 0.61, [saved_LIBS="$LIBS" LIBS="$LIBS $DBUS_LIBS" AC_CHECK_FUNCS(dbus_watch_get_unix_fd) LIBS="$saved_LIBS" ], [AC_MSG_ERROR([Cannot find dbus-1 >= 0.61, install it and rerun ./configure Please review the following errors: $DBUS_PKG_ERRORS])] ) DBUS_VERSION=`$PKG_CONFIG dbus-1 --modversion` AC_DEFINE([HAVE_DBUS], 1, [Define to 1 if DBUS IPC is to be compiled in]) fi AC_MSG_CHECKING([for whether to use GL drawing]) AC_ARG_ENABLE([gl], [ --enable-gl Enable GL drawing (with GTK HID)], [],[ case " $with_gui " in *\ gtk\ *) enable_gl=yes;; * ) enable_gl=no;; esac ]) AC_MSG_RESULT([$enable_gl]) AM_CONDITIONAL(USE_GL, test x$enable_gl = xyes) if test "x$enable_gl" = "xyes"; then case " $with_gui " in *\ gtk\ *) ;; * ) AC_MSG_ERROR([GL drawing enabled but only works with the GTK HID. Either do not use --enable-gl or enable the gtk HID.]) ;; esac AX_CHECK_GL AS_IF([test X$no_gl = Xyes], [AC_MSG_FAILURE([OpenGL is required.])]) AX_CHECK_GLU AS_IF([test X$no_glu = Xyes], [AC_MSG_FAILURE([The OpenGL GLU library is required.])]) AC_DEFINE([ENABLE_GL], 1, [Define to 1 if GL support is to be compiled in]) fi AC_MSG_CHECKING([for which printer to use]) AC_ARG_WITH([printer], [ --with-printer= Specify the printer: lpr [[default=lpr]]], [],[with_printer=lpr]) AC_MSG_RESULT([$with_printer]) case " $hid_printers " in *\ $with_printer\ * ) HIDLIST="$HIDLIST $with_printer" ;; * ) AC_MSG_ERROR([$with_printer is not a valid printer]) ;; esac AC_MSG_CHECKING([for which exporters to use]) AC_ARG_WITH([exporters], [ --with-exporters= Enable export devices: bom gerber gcode nelma png ps ipcd356 gsvit [[default=bom gerber gcode nelma png ps ipcd356 gsvit]]], [],[with_exporters=$hid_exporters]) AC_MSG_RESULT([$with_exporters]) for e in `echo $with_exporters | sed 's/,/ /g'`; do case " $hid_exporters " in *\ $e\ * ) HIDLIST="$HIDLIST $e" ;; * ) AC_MSG_ERROR([$e is not a valid exporter]) ;; esac done if test "X$enable_jpeg" = "Xno" -a "X$enable_gif" = "Xno" -a "X$enable_png" = "Xno" ; then case " ${HIDLIST} " in *\ png\ *) AC_MSG_ERROR([you have requested the png HID but turned off all output formats! If you do not want gif/jpeg/png output, use --with-exporters to list which exporters you want and do not list png there.]) ;; *) ;; esac fi for hid in $HIDLIST; do F=$srcdir/src/hid/$hid/hid.conf if test -f $F ; then echo checking $hid dependencies deps= . $F for dep in $deps; do if test "X`echo $HIDLIST | grep $dep`" = "X"; then AC_MSG_ERROR([you have requested the $hid HID but not the $dep HID, which it depends on]) fi done fi done for e in $HIDLIST; do HIDLIBS="$HIDLIBS lib$e.a" done AC_SUBST(HIDLIST) AC_SUBST(HIDLIBS) # ------------- end HID config ------------------- ###################################################################### # # desktop integration # AC_PATH_PROG(SETENV, env, []) AC_PATH_PROG(GTK_UPDATE_ICON_CACHE_BIN, gtk-update-icon-path, [true]) # Change default location for XDG files (MIME and Icons) AC_ARG_WITH(xdgdatadir, [ --with-xdgdatadir=path Change where the theme icons and mime registrations are installed [[DATADIR]]], [opt_xdgdatadir=$withval]) # Change default location for KDE data files (KDE MIME registrations) AC_ARG_WITH(kdedatadir, [ --with-kdedatadir=path Change where the KDE mime reg istrations are installed [[DATADIR]]], [opt_kdedatadir=$withval]) if test x$opt_xdgdatadir = x; then # path was not specified with --with-xdgdatadir XDGDATADIR='${datadir}' else # path WAS specified with --with-xdgdatadir XDGDATADIR="$opt_xdgdatadir" fi AC_SUBST(XDGDATADIR) if test x$opt_kdedatadir = x; then # path was not specified with --with-kdedatadir KDEDATADIR='${datadir}' else # path WAS specified with --with-kdedatadir KDEDATADIR="$opt_kdedatadir" fi AC_SUBST(KDEDATADIR) AC_ARG_ENABLE(update-desktop-database, AC_HELP_STRING([--disable-update-desktop-database], [do not update desktop database after installation]),, enable_update_desktop_database=yes) AM_CONDITIONAL(ENABLE_UPDATE_DESKTOP_DATABASE, test x$enable_update_desktop_database = xyes) if test x$enable_update_desktop_database = xyes ; then AC_PATH_PROG(UPDATE_DESKTOP_DATABASE, [update-desktop-database], no) if test $UPDATE_DESKTOP_DATABASE = no; then AC_MSG_ERROR([Cannot find update-desktop-database, make sure it is installed and in your PATH, or configure with --disable-update-desktop-database]) fi fi AC_ARG_ENABLE(update-mime-database, AC_HELP_STRING([--disable-update-mime-database], [do not update mime database after installation]),, enable_update_mime_database=yes) AM_CONDITIONAL(ENABLE_UPDATE_MIME_DATABASE, test x$enable_update_mime_database = xyes) if test x$enable_update_mime_database = xyes ; then AC_PATH_PROG(UPDATE_MIME_DATABASE, [update-mime-database], no) if test $UPDATE_MIME_DATABASE = no; then AC_MSG_ERROR([Cannot find update-mime-database, make sure it is installed and in your PATH, or configure with --disable-update-mime-database]) fi fi # ###################################################################### AC_PATH_PROGS(M4, gm4 m4, [none]) if test "X$M4" = "Xnone" ; then AC_MSG_ERROR([Did not find a m4 executible. You need to make sure that m4 is installed on your system and that m4 is in your path]) fi AC_MSG_CHECKING([if $M4 has the division involving negative numbers bug]) pcb_m4_r=`echo "eval(-2/2)" | $M4` if test "$pcb_m4_r" != "-1" ; then AC_MSG_RESULT([yes]) AC_MSG_ERROR([It appears that $M4 has a bug involving division with negative numbers. In particular it just returned the result that -2/2 = $pcb_m4_r instead of -1. This is a known bug in GNU m4-1.4.9. Please install a non-broken m4.]) else AC_MSG_RESULT([no]) fi AC_PATH_PROGS(WISH, wish wish85 wish8.5 wish83 wish8.3 wish80 wish8.0 cygwish83 cygwish80,[none]) if test "X$WISH" = "Xnone" ; then AC_MSG_ERROR([Did not find the wish executible. You need to make sure that tcl is installed on your system and that wish is in your path]) fi AC_DEFINE_UNQUOTED(M4,$M4,[m4 executible]) GNUM4=$M4 AC_SUBST(GNUM4) AC_DEFINE_UNQUOTED(GNUM4,"$M4",[m4 program used by pcb]) AC_PATH_PROG(PDFLATEX, pdflatex, notfound) AM_CONDITIONAL(MISSING_PDFLATEX, test x$PDFLATEX = xnotfound) AC_PATH_PROG(TEXI2DVI, texi2dvi, notfound) AM_CONDITIONAL(MISSING_TEXI2DVI, test x$TEXI2DVI = xnotfound) AC_PATH_PROG(PS2PDF, ps2pdf, notfound) AM_CONDITIONAL(MISSING_PS2PDF, test x$PS2PDF = xnotfound) # used to build some of the getting started guide AC_PATH_PROG(GSCHEM, gschem, notfound) AM_CONDITIONAL(MISSING_GSCHEM, test x$GSCHEM = xnotfound) if test "X$docs_yesno" = "Xyes" -a "X$pcb_git_version" = "Xyes" ; then if test "$PDFLATEX" = "notfound" -o "$TEXI2DVI" = "notfound" -o "$PS2PDF" = "notfound" ; then AC_MSG_ERROR([It appears that you are building from a source tree obtained via git but you do not have the required tools installed to build the documentation. Here is a list of tools and the detected values: PDFLATEX: $PDFLATEX TEXI2DVI: $TEXI2DVI PS2PDF: $PS2PDF GSCHEM: $GSCHEM Either make sure these tools are installed or disable building and installing the documentation by using the --disable-doc configure option. ]) fi fi ############################################################################ # # These checks are for tools used by the testsuite. It will not be fatal # if these are missing because this is primarily for developer use. It is # possible that we might add some --enable flag in the future that forces # full tools for development work. # Check for ImageMagick tools used by the testsuite AC_PATH_PROG(IM_ANIMATE, animate, notfound) AC_PATH_PROG(IM_COMPARE, compare, notfound) AC_PATH_PROG(IM_COMPOSITE, composite, notfound) AC_PATH_PROG(IM_CONVERT, convert, notfound) AC_PATH_PROG(IM_DISPLAY, display, notfound) AC_PATH_PROG(IM_MONTAGE, montage, notfound) AC_PATH_PROG(XHOST, xhost, notfound) missing_magick="" test "${IM_ANIMATE}" != "notfound" || missing_magick="${missing_magick} animate" test "${IM_COMPARE}" != "notfound" || missing_magick="${missing_magick} compare" test "${IM_COMPOSITE}" != "notfound" || missing_magick="${missing_magick} composite" test "${IM_CONVERT}" != "notfound" || missing_magick="${missing_magick} convert" test "${IM_DISPLAY}" != "notfound" || missing_magick="${missing_magick} display" test "${IM_MONTAGE}" != "notfound" || missing_magick="${missing_magick} montage" AC_MSG_CHECKING([if all ImageMagick tools needed for the testsuite were found]) if test "X${missing_magick}" != "X" ; then AC_MSG_RESULT([no. The testsuite will be disabled because the following tools from the ImageMagick suite were not found: ${missing_magick} No loss in pcb functionality should be experienced, you just will not be able to run the full regression testsuite. ]) have_magick=no else AC_MSG_RESULT([yes]) have_magick=yes fi have_test_tools=yes test $have_magick = yes || have_test_tools=no # the RS274-X export HID is partially checked by looking at the result with # gerbv AC_PATH_PROG(GERBV, gerbv, notfound) test $GERBV != notfound || have_test_tools=no AM_CONDITIONAL(HAVE_TEST_TOOLS, test x$have_test_tools = xyes) AC_MSG_CHECKING([if all the required testsuite tools were found]) if test x$have_test_tools = xyes ; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no -- the testsuite will be disabled]) fi # ############################################################################ dnl Checks for libraries. AC_CHECK_LIB(m, sqrt) AC_CHECK_LIB(dl, dlopen) AC_CHECK_LIB(xnet, gethostbyname) AC_CHECK_LIB(fl, yywrap) dnl Checks for functions AC_CHECK_FUNCS(getline) AC_CHECK_FUNCS(strcasestr) AC_CHECK_FUNCS(strerror) AC_CHECK_FUNCS(regcomp re_comp) AC_CHECK_FUNCS(logf expf rint) AC_CHECK_FUNCS(vsnprintf) AC_CHECK_FUNCS(getpwuid getcwd) AC_CHECK_FUNCS(rand random) AC_CHECK_FUNCS(stat) AC_CHECK_FUNCS(mkdtemp) # normally used for all file i/o AC_CHECK_FUNCS(popen) # for lrealpath.c AC_CHECK_FUNCS(realpath canonicalize_file_name) libiberty_NEED_DECLARATION(canonicalize_file_name) # for pcb_spawnvp in action.c on Windows AC_CHECK_FUNCS(_spawnvp) AC_HEADER_STDC AC_CHECK_HEADERS(limits.h locale.h string.h sys/types.h regex.h pwd.h) AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h sys/param.h sys/times.h sys/wait.h) AC_CHECK_HEADERS(dlfcn.h) if test "x${WIN32}" = "xyes" ; then AC_CHECK_HEADERS(windows.h) fi # Search for glib PKG_CHECK_MODULES(GLIB, glib-2.0, , [AC_MSG_RESULT([Note: cannot find glib-2.0. You may want to review the following errors: $GLIB_PKG_ERRORS])] ) need_gdlib=no with_gif=no with_png=no with_jpeg=no for e in $HIDLIST; do case $e in lesstif ) AC_PATH_XTRA save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$X_CFLAGS" AC_CHECK_LIB(X11, XOpenDisplay, , , $X_LIBS) AC_CHECK_LIB(ICE, main, , , $X_LIBS) AC_CHECK_LIB(SM, main, , , $X_LIBS) AC_CHECK_LIB(Xext, main, , , $X_LIBS) AC_CHECK_LIB(Xt, XtOpenDisplay, , , $X_LIBS) AC_CHECK_LIB(Xmu, main, , , $X_LIBS) AC_CHECK_LIB(Xpm, main, , , $X_LIBS) AC_CHECK_LIB(Xm, XmCreateMainWindow, , , $X_LIBS) CPPFLAGS="$save_CPPFLAGS" case $ac_cv_lib_Xm_XmCreateMainWindow in no ) AC_MSG_ERROR([You don't seem to have the Lesstif development environment installed.]) ;; * ) ;; esac AC_CHECK_HEADERS(Xm/Xm.h) case $ac_cv_header_Xm_Xm_h in no ) AC_MSG_ERROR([You don't seem to have the Lesstif development environment installed.]) ;; * ) ;; esac ;; gtk ) # Check for pkg-config PKG_PROG_PKG_CONFIG if test -z "$PKG_CONFIG"; then AC_MSG_ERROR([Cannot find pkg-config, make sure it is installed and in your PATH]) fi PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.18.0, , [AC_MSG_ERROR([Cannot find gtk+ >= 2.18.0, install it and rerun ./configure Please review the following errors: $GTK_PKG_ERRORS])] ) GTK_VERSION=`$PKG_CONFIG gtk+-2.0 --modversion` GLIB_VERSION=`$PKG_CONFIG glib-2.0 --modversion` if test "x$enable_gl" = "xyes"; then # Check for GtkGLExt PKG_CHECK_MODULES(GTKGLEXT, gtkglext-1.0 >= 1.0.0, , [AC_MSG_ERROR([ *** Required version of gtkglext is not installed - please install first *** Please review the following errors: $GTKGLEXT_PKG_ERRORS])] ) GTKGLEXT_VER=`$PKG_CONFIG gtkglext-1.0 --modversion` fi ;; png) need_gdlib=yes AC_MSG_CHECKING([if GIF output from the png HID is desired]) AC_ARG_ENABLE([gif], [ --disable-gif Disable support for gif output when the png HID is used [[default=include gif support]]], [ if test "X$enable_gif" != "Xno" ; then AC_MSG_RESULT([yes]) with_gif=yes else AC_MSG_RESULT([no]) fi ], [ AC_MSG_RESULT([yes]) with_gif=yes ]) AC_MSG_CHECKING([if JPEG output from the png HID is desired]) AC_ARG_ENABLE([jpeg], [ --disable-jpeg Disable support for JPEG output when the png HID is used [[default=include JPEG support]]], [ if test "X$enable_jpeg" != "Xno" ; then AC_MSG_RESULT([yes]) with_jpeg=yes else AC_MSG_RESULT([no]) fi ], [ AC_MSG_RESULT([yes]) with_jpeg=yes ]) AC_MSG_CHECKING([if PNG output from the png HID is desired]) AC_ARG_ENABLE([png], [ --disable-png Disable support for PNG output when the png HID is used [[default=include PNG support]]], [ if test "X$enable_png" != "Xno" ; then AC_MSG_RESULT([yes]) with_png=yes else AC_MSG_RESULT([no]) fi ], [ AC_MSG_RESULT([yes]) with_png=yes ]) ;; gcode|nelma) need_gdlib=yes with_png=yes ;; esac done if test "$need_gdlib" = "yes"; then # Search for glib PKG_CHECK_MODULES(GDLIB, gdlib,[found_gdlib=yes] , [found_gdlib=no]) if test "X$found_gdlib" = "Xno"; then # older installs came with gdlib-config and not the .pc file # to work with pkg-config AC_PATH_PROG([GDLIB_CONFIG], [gdlib-config], [notfound]) if test "$GDLIB_CONFIG" = "notfound" ; then AC_MSG_ERROR([cannot find gdlib-config. gdlib is required for gcode, nelma, png HIDs You may want to review the following errors from $PKG_CONFIG: $GDLIB_PKG_ERRORS]) else AC_MSG_CHECKING([for gdlib cflags]) GDLIB_CFLAGS=`${GDLIB_CONFIG} --cflags` AC_MSG_RESULT([$GDLIB_CFLAGS]) AC_MSG_CHECKING([for gdlib libraries]) GDLIB_LIBS=`${GDLIB_CONFIG} --libs` AC_MSG_RESULT([$GDLIB_LIBS]) AC_MSG_CHECKING([for gdlib ldflags]) GDLIB_LDFLAGS=`${GDLIB_CONFIG} --ldflags` AC_MSG_RESULT([$GDLIB_LDFLAGS]) fi fi save_LIBS="$LIBS" LIBS="$LIBS $GDLIB_LDFLAGS $GDLIB_LIBS" # some older installs, Ubuntu Precise for example, leave off the "-lgd" part. # try to see if it needs to be added. However this is currently broken # under cygwin cross building for mingw because of interactions with # __imp__ prefix added in the libgd.a static library. Look at the declspec # stuff in the mingw gd.h file. if test "x$WIN32" = "xno" ; then before_LIBS="$LIBS" AC_SEARCH_LIBS([gdImageCreate],[gd],[],[ AC_MSG_ERROR([Unable to figure out how to link gd applications. It is likely that your system has a broken gdlib-config or gdlib.pc file used by pkg-config. ])],[]) if test "$LIBS" != "${before_LIBS}" ; then GDLIB_LIBS="${GDLIB_LIBS} -lgd" fi fi if test "X$with_gif" = "Xyes" ; then AC_CHECK_FUNCS(gdImageGif) if test "$ac_cv_func_gdImageGif" != "yes"; then AC_MSG_ERROR([Your gd installation does not appear to include gif support. You may need to update your installation of gd or disable gif export with --disable-gif]) fi fi if test "X$with_jpeg" = "Xyes" ; then AC_CHECK_FUNCS(gdImageJpeg) if test "$ac_cv_func_gdImageJpeg" != "yes"; then AC_MSG_ERROR([Your gd installation does not appear to include JPEG support. You may need to update your installation of gd or disable JPEG export with --disable-jpeg]) fi fi if test "X$with_png" = "Xyes" ; then AC_CHECK_FUNCS(gdImagePng) if test "$ac_cv_func_gdImagePng" != "yes"; then AC_MSG_ERROR([Your gd installation does not appear to include PNG support. You may need to update your installation of gd or disable PNG export with --disable-png]) fi fi LIBS="$save_LIBS" fi AM_CONDITIONAL(PNG, test x$with_png = xyes) AM_CONDITIONAL(GIF, test x$with_gif = xyes) # ------------- check if png previews should be built for pcblib-newlib AC_MSG_CHECKING([if the m4lib to newlib export should create png previews]) AC_ARG_ENABLE( [m4lib-png], [ --enable-m4lib-png Enable creating png previews for the m4 library], [],[enable_m4lib_png=no]) AC_MSG_RESULT([$enable_m4lib_png]) AM_CONDITIONAL(PNG_PREVIEW, test x$enable_m4lib_png = xyes) # Run away.... more ugly stuff here. By default we don't actually build # pcblib-newlib from pcblib unless we are building from cvs or git sources. # The reason is it takes a while and requires the png HID. The problem is, # what if someone wants to use --enable-m4lib-png but the tarball was built # without the previews. Or, what if someone does not want the PNG previews # but the person building the tarball included them. Ugh! So what the following # code attempts to do is detect that mismatch situation. Note that we only # want to kick this code in when *not* building from git or cvs sources. build_pcblib_newlib=no if test "$pcb_sources" = "tarball" ; then AC_MSG_CHECKING([If pcblib-newlib was built with png previews]) stamp=$srcdir/lib/pcblib-newlib.stamp if test ! -f ${stamp} ; then AC_MSG_RESULT([unknown, missing ${stamp}]) build_pcblib_newlib=yes else if test "`cat ${stamp}`" = "png-preview=yes" ; then AC_MSG_RESULT([yes]) # lib exists and built with preview. # if we don't want the preview, than rebuild if test x$enable_m4lib_png != xyes ; then build_pcblib_newlib=yes fi else AC_MSG_RESULT([no]) # lib exists and built without preview. # if we want the preview, than rebuild if test x$enable_m4lib_png = xyes ; then build_pcblib_newlib=yes fi fi fi else build_pcblib_newlib=yes fi AC_MSG_CHECKING([If pcblib-newlib needs to be rebuilt]) AC_MSG_RESULT([$build_pcblib_newlib]) AM_CONDITIONAL(BUILD_PCBLIB_NEWLIB, test x$build_pcblib_newlib = xyes) if test "X$cross_compiling" = "Xyes" ; then # we are cross compiling so we will need a build host binary for pcb AC_PATH_PROG(PCB, [pcb], [notfound]) else PCB="\${top_builddir}/src/pcb" fi AC_SUBST(PCB) # now make see how essential it was that we have a pcb executable for the build # host if test "X$pcb_git_version" = "Xyes" ; then if test "X$docs_yesno" = "Xyes" -o "X$enable_m4lib_png" = "Xyes" ; then if test "$PCB" = "notfound" ; then AC_MSG_ERROR([You have selected a build with m4lib png previews enabled and/or with building the documentation enabled but you also appear to be cross-compiling. For this to work, you must have a pcb installed that can run on this machine (the build machine) because it is needed for generating library footprint png previews as well as some of the figures in the documentation. If you wish to skip building the documentation and the footprint previews then add --disable-doc --disable-m4lib-png This will allow your cross build to work.]) fi fi fi # ------------- Xrender ------------------- have_xrender=no AC_CHECK_LIB(Xrender,XRenderQueryExtension,have_xrender=yes,have_xrender=no,$X_LIBS) AC_ARG_ENABLE([xrender], [ --disable-xrender Compile and link with Xrender [default=yes]]) case "$have_xrender:$enable_xrender" in no:* ) ;; *:no ) ;; * ) X_LIBS="-lXrender $X_LIBS" AC_DEFINE([HAVE_XRENDER], 1, [Define to 1 if Xrender is available]) ;; esac # ------------- Xinerama ------------------- have_xinerama=no AC_CHECK_LIB(Xinerama,XineramaQueryExtension,have_xinerama=yes,have_xinerama=no,$X_LIBS) AC_ARG_ENABLE([xinerama], [ --disable-xinerama Compile and link with Xinerama [default=yes]]) case "$have_xinerama:$enable_xinerama" in no:* ) ;; *:no ) ;; * ) X_LIBS="-lXinerama $X_LIBS" AC_DEFINE([HAVE_XINERAMA], 1, [Define to 1 if Xinerama is available]) ;; esac # ------------- dmalloc ------------------- dnl dmalloc checks with_dmalloc=no AC_MSG_CHECKING([if dmalloc debugging should be enabled]) AC_ARG_ENABLE([dmalloc], [ --enable-dmalloc Compile and link with dmalloc for malloc debugging [default=no]], [ if test "X$enable_dmalloc" != "Xno" ; then AC_MSG_RESULT([yes]) AC_CHECK_HEADER(dmalloc.h,, AC_MSG_ERROR([You have requested dmalloc debugging but dmalloc.h could not be found])) AC_CHECK_LIB(dmalloc,main,, AC_MSG_ERROR([You have requested dmalloc debugging but -ldmalloc could not be found])) DMALLOC_LIBS="-ldmalloc" with_dmalloc=yes else AC_MSG_RESULT([no]) DMALLOC_LIBS="" fi ], [ AC_MSG_RESULT([no]) DMALLOC_LIBS="" ]) # ------------- ElectricFence ------------------- dnl ElectricFence checks with_efence=no AC_MSG_CHECKING([if ElectricFence debugging should be enabled]) AC_ARG_ENABLE([efence], [ --enable-efence Link with ElectricFence for malloc debugging [default=no]], [ if test "X$enable_efence" != "Xno" ; then AC_MSG_RESULT([yes]) AC_CHECK_LIB(efence,main,, AC_MSG_ERROR([You have requested ElectricFence debugging but -lefence could not be found])) with_efence=yes else AC_MSG_RESULT([no]) fi ], [ AC_MSG_RESULT([no]) ]) # ------------- Enable Debug code ------------------- AC_MSG_CHECKING([for whether to enable debugging code]) AC_ARG_ENABLE([debug], [ --enable-debug Enable debugging code], [],[enable_debug=no]) AC_MSG_RESULT([$enable_debug]) AM_CONDITIONAL(DEBUG_BUILD, test x$enable_debug = xyes) # ------------- mkdir required for win32 compatibility ------------ # WIN32 mkdir takes only one argument, POSIX takes two. # #include "misc.h" where mkdir is required. m4_include([m4/m4_ax_func_mkdir.m4]) AX_FUNC_MKDIR # ------------- Type used for "Coord" type ------------------- AC_CHECK_HEADERS(stdint.h) AC_ARG_ENABLE([coord64], [ --enable-coord64 Force 64-bit coordinate types], [],[enable_coord64=no]) AC_ARG_ENABLE([coord32], [ --enable-coord32 Force 32-bit coordinate types], [],[enable_coord32=no]) COORDTYPE="long" echo "$enable_coord32:$enable_coord64:$ac_cv_header_stdint_h" case "$enable_coord32:$enable_coord64:$ac_cv_header_stdint_h" in yes:no:yes ) COORD_TYPE="int32_t" COORD_MAX="INT32_MAX" ;; no:yes:yes ) COORD_TYPE="int64_t" COORD_MAX="INT64_MAX" ;; yes:no:no ) COORD_TYPE="int" COORD_MAX="INT_MAX" ;; no:yes:no ) COORD_TYPE="long long" COORD_MAX="LLONG_MAX" ;; yes:yes:* ) AC_MSG_ERROR("*** cannot require both 32 and 64 bit coordinates") ;; *:*:* ) COORD_TYPE="long" COORD_MAX="LONG_MAX" ;; esac AC_DEFINE_UNQUOTED([COORD_TYPE],[$COORD_TYPE], [C type for Coordinates]) AC_DEFINE_UNQUOTED([COORD_MAX],[$COORD_MAX], [Maximum value of coordinate type]) # ------------- Complete set of CPPFLAGS and LIBS ------------------- CPPFLAGS="$CPPFLAGS $X_CFLAGS $DBUS_CFLAGS $GDLIB_CFLAGS $GLIB_CFLAGS $GTK_CFLAGS $GD_CFLAGS $CAIRO_CFLAGS $GTKGLEXT_CFLAGS $GLU_CFLAGS $GL_CFLAGS" LIBS="$LIBS $XM_LIBS $DBUS_LIBS $X_LIBS $GDLIB_LDFLAGS $GDLIB_LIBS $GLIB_LIBS $GTK_LIBS $DMALLOC_LIBS $GD_LIBS $INTLLIBS $CAIRO_LIBS $GTKGLEXT_LIBS $GLU_LIBS $GL_LIBS" # if we have gcc then add -Wall if test "x$GCC" = "xyes"; then # see about adding some extra checks if the compiler takes them for flag in -Wall ; do case " ${CFLAGS} " in *\ ${flag}\ *) # flag is already present ;; *) AC_MSG_CHECKING([if the compiler accepts ${flag}]) ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS ${flag}" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) CFLAGS="$ac_save_CFLAGS" ] ) ;; esac done fi CXXFLAGS="$CFLAGS" # Now add C-specific flags if test "x$GCC" = "xyes"; then # see about adding some extra checks if the compiler takes them for flag in -Wdeclaration-after-statement ; do case " ${CFLAGS} " in *\ ${flag}\ *) # flag is already present ;; *) AC_MSG_CHECKING([if the compiler accepts ${flag}]) ac_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS ${flag}" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) CFLAGS="$ac_save_CFLAGS" ] ) ;; esac done fi # See if we are building gcc with C++. AC_ARG_ENABLE(build-with-cxx, [ --enable-build-with-cxx build with C++ compiler instead of C compiler], ENABLE_BUILD_WITH_CXX=$enableval, ENABLE_BUILD_WITH_CXX=no) case "$ENABLE_BUILD_WITH_CXX" in yes) CC_OR_CXX="$CXX" ;; no) CC_OR_CXX="$CC" ;; esac AC_SUBST(CC_OR_CXX) # font filename FONTFILENAME=${FONTFILENAME:-"default_font"} AC_SUBST(FONTFILENAME) AC_DEFINE_UNQUOTED(FONTFILENAME,"$FONTFILENAME",[File for default font]) # standard autoconf variables CPPFLAGS="$CPPFLAGS -DPREFIXDIR=\\\"\${prefix}\\\"" CPPFLAGS="$CPPFLAGS -DBINDIR=\\\"\${bindir}\\\"" CPPFLAGS="$CPPFLAGS -DHOST=\\\"\${host}\\\"" # directory for old-style library and for fonts PCBLIBDIR=${datadir}/pcb AC_SUBST(PCBLIBDIR) #AC_DEFINE_UNQUOTED(PCBLIBDIR,"$PCBLIBDIR",[Library directory]) CPPFLAGS="$CPPFLAGS -DPCBLIBDIR=\\\"$PCBLIBDIR\\\"" # name for old-style library LIBRARYFILENAME=pcblib AC_SUBST(LIBRARYFILENAME) AC_DEFINE_UNQUOTED(LIBRARYFILENAME,"$LIBRARYFILENAME",[library file name]) # directory for new library PCBTREEDIR=${datadir}/pcb/newlib PCBTREEPATH=${PCBTREEDIR}:${PCBLIBDIR}/pcblib-newlib PCBTREEDIR=${PCBTREEDIR:-"$PCBTREEDIR"} AC_SUBST(PCBTREEDIR) AC_SUBST(PCBTREEPATH) #AC_DEFINE_UNQUOTED(PCBTREEDIR,"$PCBLIB",[top directory for new style pcb library]) CPPFLAGS="$CPPFLAGS -DPCBTREEDIR=\\\"$PCBTREEDIR\\\"" CPPFLAGS="$CPPFLAGS -DPCBTREEPATH=\\\"$PCBTREEPATH\\\"" # Figure out relative paths AC_MSG_CHECKING([for the bindir to pcblibdir relative path]) adl_COMPUTE_RELATIVE_PATHS([bindir:PCBLIBDIR:bindir_to_pcblibdir]) adl_NORMALIZE_PATH([bindir_to_pcblibdir], [$PCB_DIR_SEPARATOR_S]) AC_MSG_RESULT([$bindir_to_pcblibdir]) AC_DEFINE_UNQUOTED(BINDIR_TO_PCBLIBDIR, "$bindir_to_pcblibdir", [Relative path from bindir to pcblibdir]) AC_MSG_CHECKING([for the bindir to pcbtreedir relative path]) adl_COMPUTE_RELATIVE_PATHS([bindir:PCBTREEDIR:bindir_to_pcbtreedir]) adl_NORMALIZE_PATH([bindir_to_pcbtreedir], [$PCB_DIR_SEPARATOR_S]) AC_MSG_RESULT([$bindir_to_pcbtreedir]) AC_DEFINE_UNQUOTED(BINDIR_TO_PCBTREEDIR, "$bindir_to_pcbtreedir", [Relative path from bindir to pcbtreedir]) AC_MSG_CHECKING([for the bindir to exec_prefix relative path]) adl_COMPUTE_RELATIVE_PATHS([bindir:exec_prefix:bindir_to_execprefix]) adl_NORMALIZE_PATH([bindir_to_execprefix], [$PCB_DIR_SEPARATOR_S]) AC_MSG_RESULT([$bindir_to_execprefix]) AC_DEFINE_UNQUOTED(BINDIR_TO_EXECPREFIX, "$bindir_to_execprefix", [Relative path from bindir to exec_prefix]) BTNMOD=${BTNMOD:-"Mod1"} AC_SUBST(BTNMOD) TOPDIRS= for dir in src lib newlib doc example tools tutorial README_FILES do test -d $dir/. && TOPDIRS="$TOPDIRS $dir" done AC_SUBST(TOPDIRS) AC_CONFIG_FILES(Makefile data/Makefile intl/Makefile po/Makefile.in) if test -d $srcdir/README_FILES; then AC_CONFIG_FILES(README_FILES/Makefile) fi if test -d $srcdir/doc; then AC_CONFIG_FILES(doc/Makefile) fi if test -d $srcdir/doc/gs; then AC_CONFIG_FILES(doc/gs/Makefile) AC_CONFIG_FILES(doc/gs/gafrc) AC_CONFIG_FILES(doc/gs/gschemrc) fi if test -d $srcdir/example; then AC_CONFIG_FILES(example/Makefile) AC_CONFIG_FILES(example/libraries/Makefile) fi if test -d $srcdir/lib; then AC_CONFIG_FILES(lib/CreateLibraryContents.sh) AC_CONFIG_FILES(lib/CreateLibrary.sh) AC_CONFIG_FILES(lib/ListLibraryContents.sh) AC_CONFIG_FILES(lib/Makefile) AC_CONFIG_FILES(lib/QueryLibrary.sh) AC_CONFIG_FILES(lib/qfp-ui) fi if test -d $srcdir/newlib; then AC_CONFIG_FILES(newlib/2_pin_thru-hole_packages/Makefile) AC_CONFIG_FILES(newlib/Makefile) AC_CONFIG_FILES(newlib/connectors/Makefile) AC_CONFIG_FILES(newlib/crystal/Makefile) AC_CONFIG_FILES(newlib/electro-optics/Makefile) AC_CONFIG_FILES(newlib/headers/Makefile) AC_CONFIG_FILES(newlib/keystone/Makefile) AC_CONFIG_FILES(newlib/msp430/Makefile) AC_CONFIG_FILES(newlib/not_vetted_ingo/Makefile) AC_CONFIG_FILES(newlib/sockets/Makefile) AC_CONFIG_FILES(newlib/tests/Makefile) fi AC_CONFIG_FILES(src/Makefile) AC_CONFIG_FILES(src/icons/Makefile) if test -d $srcdir/tools; then AC_CONFIG_FILES(tools/Makefile) fi if test -d $srcdir/tutorial; then AC_CONFIG_FILES(tutorial/Makefile) fi dnl testsuite AC_CONFIG_FILES(tests/Makefile) dnl GTS 0.7.6 - http://gts.sourceforge.net/ AC_CONFIG_FILES(gts/Makefile) dnl win32 build scripts AC_CONFIG_FILES(w32/Makefile) dnl for building under cygwin AC_CONFIG_FILES(win32/Makefile) AC_OUTPUT with_gui=`echo $with_gui` with_printer=`echo $with_printer` with_exporters=`echo $with_exporters | sed 's/,/ /g'` expandedXDGDATADIR=`eval "echo $XDGDATADIR"` expandedKDEDATADIR=`eval "echo $KDEDATADIR"` AC_MSG_RESULT([ ** Configuration summary for $PACKAGE $VERSION: Cross Compiling: $cross_compiling CC: $CC CXX: $CXX CPPFLAGS: $CPPFLAGS CFLAGS: $CFLAGS CXXFLAGS: $CXXFLAGS LIBS: $LIBS PCB: $PCB GUI: $with_gui Printer: $with_printer Exporters: $with_exporters Coordinate type: $COORD_TYPE Source tree distribution: $pcb_sources Build documentation: $docs_yesno Build toporouter: $enable_toporouter Enable toporouter output: $enable_toporouter_output xdg data directory: $expandedXDGDATADIR KDE data directory: $expandedKDEDATADIR dmalloc debugging: $with_dmalloc ElectricFence debugging: $with_efence Regression tests enabled: $have_test_tools ]) pcb-4.2.2/depcomp0000775000076400007640000003677411660653114010617 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2005-02-09.22 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program 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 General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test -f "$tmpdepfile"; then : else stripped=`echo "$stripped" | sed 's,^.*/,,'` tmpdepfile="$stripped.u" fi if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then outname="$stripped.o" # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mecanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # X makedepend shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes ;; esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. "$@" || exit $? IFS=" " for arg do case "$arg" in "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: pcb-4.2.2/src/0000775000076400007640000000000013611113567010071 500000000000000pcb-4.2.2/src/mymem.h0000664000076400007640000000700713434555140011312 00000000000000/*! * \file src/mymem.h * * \brief Prototypes for memory routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_MYMEM_H #define PCB_MYMEM_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "global.h" /* --------------------------------------------------------------------------- * number of additional objects that are allocated with one system call */ #define STEP_ELEMENT 50 #define STEP_DRILL 30 #define STEP_POINT 100 #define STEP_SYMBOLLINE 10 #define STEP_SELECTORENTRY 128 #define STEP_REMOVELIST 500 #define STEP_UNDOLIST 500 #define STEP_POLYGONPOINT 10 #define STEP_POLYGONHOLEINDEX 10 #define STEP_LIBRARYMENU 10 #define STEP_LIBRARYENTRY 20 #define STEP_RUBBERBAND 100 #define STRDUP(x) (((x) != NULL) ? strdup (x) : NULL) /*! * \brief Dynamic string type. */ typedef struct { size_t MaxLength; char *Data; } DynamicStringType; RubberbandType * GetRubberbandMemory (void); PinType * GetPinMemory (ElementType *); PadType * GetPadMemory (ElementType *); PinType * GetViaMemory (DataType *); LineType * GetLineMemory (LayerType *); ArcType * GetArcMemory (LayerType *); RatType * GetRatMemory (DataType *); TextType * GetTextMemory (LayerType *); PolygonType * GetPolygonMemory (LayerType *); PointType * GetPointMemoryInPolygon (PolygonType *); Cardinal *GetHoleIndexMemoryInPolygon (PolygonType *); ElementType * GetElementMemory (DataType *); BoxType * GetBoxMemory (BoxListType *); ConnectionType * GetConnectionMemory (NetType *); NetType * GetNetMemory (NetListType *); NetListType * GetNetListMemory (NetListListType *); LibraryMenuType * GetLibraryMenuMemory (LibraryType *); LibraryEntryType * GetLibraryEntryMemory (LibraryMenuType *); ElementType **GetDrillElementMemory (DrillType *); PinType ** GetDrillPinMemory (DrillType *); DrillType * GetDrillInfoDrillMemory (DrillInfoType *); void **GetPointerMemory (PointerListType *); void FreePolygonMemory (PolygonType *); void FreeElementMemory (ElementType *); void FreePCBMemory (PCBType *); void FreeBoxListMemory (BoxListType *); void FreeNetListListMemory (NetListListType *); void FreeNetListMemory (NetListType *); void FreeNetMemory (NetType *); void FreeDataMemory (DataType *); void FreeLibraryMemory (LibraryType *); void FreePointerListMemory (PointerListType *); void DSAddCharacter (DynamicStringType *, char); void DSAddString (DynamicStringType *, const char *); void DSClearString (DynamicStringType *); char *StripWhiteSpaceAndDup (const char *); #ifdef NEED_STRDUP char *strdup (const char *); #endif #ifndef HAVE_LIBDMALLOC #define malloc(x) calloc(1,(x)) #endif #endif pcb-4.2.2/src/set.c0000664000076400007640000002250713533277055010764 00000000000000/*! * \file src/set.c * * \brief Routines to update widgets and global settings (except output * window and dialogs). * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #ifdef HAVE_STRING_H #include #endif #include "global.h" #include "action.h" #include "buffer.h" #include "compat.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "error.h" #include "find.h" #include "flags.h" #include "misc.h" #include "move.h" #include "set.h" #include "undo.h" #include "pcb-printf.h" #ifdef HAVE_LIBDMALLOC #include #endif static int mode_position = 0; static int mode_stack[MAX_MODESTACK_DEPTH]; /*! * \brief Sets cursor grid with respect to grid offset values. */ void SetGrid (Coord Grid, bool align) { char *grid_string; if (Grid >= 1 && Grid <= MAX_GRID) { if (align) { PCB->GridOffsetX = Crosshair.X % Grid; PCB->GridOffsetY = Crosshair.Y % Grid; } PCB->Grid = Grid; grid_string = pcb_g_strdup_printf ("%mr", Grid); if (grid_string) AttributePut (PCB, "PCB::grid::size", grid_string); g_free (grid_string); if (Settings.DrawGrid) Redraw (); } } /*! * \brief Sets a new line thickness. */ void SetLineSize (Coord Size) { if (Size >= MIN_LINESIZE && Size <= MAX_LINESIZE) { Settings.LineThickness = Size; if (TEST_FLAG (AUTODRCFLAG, PCB)) FitCrosshairIntoGrid (Crosshair.X, Crosshair.Y); } } /*! * \brief Sets a new via thickness. */ void SetViaSize (Coord Size, bool Force) { if (Force || (Size <= MAX_PINORVIASIZE && Size >= MIN_PINORVIASIZE && Size >= Settings.ViaDrillingHole)) { Settings.ViaThickness = Size; } } /*! * \brief Sets a new via drilling hole. */ void SetViaDrillingHole (Coord Size, bool Force) { if (Force || (Size <= MAX_PINORVIASIZE && Size >= MIN_PINORVIAHOLE && Size <= Settings.ViaThickness)) { Settings.ViaDrillingHole = Size; } } void SetViaMaskAperture(Coord Size) { Settings.ViaMaskAperture = Size; } void pcb_use_route_style (RouteStyleType * rst) { Settings.LineThickness = rst->Thick; Settings.ViaThickness = rst->Diameter; Settings.ViaDrillingHole = rst->Hole; Settings.Keepaway = rst->Keepaway; Settings.ViaMaskAperture = rst->ViaMask; } /*! * \brief Sets a keepaway width. */ void SetKeepawayWidth (Coord Width) { if (Width <= MAX_LINESIZE) { Settings.Keepaway = Width; } } /*! * \brief Sets a text scaling. */ void SetTextScale (int Scale) { if (Scale <= MAX_TEXTSCALE && Scale >= MIN_TEXTSCALE) { Settings.TextScale = Scale; } } /*! * \brief Sets or resets changed flag and redraws status. */ void SetChangedFlag (bool New) { if (PCB->Changed != New) { PCB->Changed = New; } } /*! * \brief Sets a new buffer number. */ void SetBufferNumber (int Number) { if (Number >= 0 && Number < MAX_BUFFER) { Settings.BufferNumber = Number; /* do an update on the crosshair range */ crosshair_update_range(); } } /*! * \brief Save mode. */ void SaveMode (void) { mode_stack[mode_position] = Settings.Mode; if (mode_position < MAX_MODESTACK_DEPTH - 1) mode_position++; } /*! * \brief Restore mode. */ void RestoreMode (void) { if (mode_position == 0) { Message ("hace: underflow of restore mode\n"); return; } SetMode (mode_stack[--mode_position]); } /*! * \brief Set a new mode and update X cursor. * * Protect the cursor while changing the mode. * * Perform some additional stuff depending on the new mode. * * Reset 'state' of attached objects. */ void SetMode (int Mode) { static bool recursing = false; if (recursing) return; recursing = true; notify_crosshair_change (false); addedLines = 0; Crosshair.AttachedObject.Type = NO_TYPE; Crosshair.AttachedObject.State = STATE_FIRST; Crosshair.AttachedPolygon.PointN = 0; if (PCB->RatDraw) { if (Mode == ARC_MODE || Mode == RECTANGLE_MODE || Mode == VIA_MODE || Mode == POLYGON_MODE || Mode == POLYGONHOLE_MODE || Mode == TEXT_MODE || Mode == INSERTPOINT_MODE || Mode == THERMAL_MODE) { Message (_("That mode is NOT allowed when drawing ratlines!\n")); Mode = NO_MODE; } } if (Settings.Mode == LINE_MODE && Mode == ARC_MODE && Crosshair.AttachedLine.State != STATE_FIRST) { Crosshair.AttachedLine.State = STATE_FIRST; Crosshair.AttachedBox.State = STATE_SECOND; Crosshair.AttachedBox.Point1.X = Crosshair.AttachedBox.Point2.X = Crosshair.AttachedLine.Point1.X; Crosshair.AttachedBox.Point1.Y = Crosshair.AttachedBox.Point2.Y = Crosshair.AttachedLine.Point1.Y; AdjustAttachedObjects (); } else if (Settings.Mode == ARC_MODE && Mode == LINE_MODE && Crosshair.AttachedBox.State != STATE_FIRST) { Crosshair.AttachedBox.State = STATE_FIRST; Crosshair.AttachedLine.State = STATE_SECOND; Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X = Crosshair.AttachedBox.Point1.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y = Crosshair.AttachedBox.Point1.Y; Settings.Mode = Mode; AdjustAttachedObjects (); } /* Cancel rubberband move */ else if (Settings.Mode == MOVE_MODE) MoveObjectAndRubberband (Crosshair.AttachedObject.Type, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, Crosshair.AttachedObject.Ptr3, 0, 0); else { if (Settings.Mode == ARC_MODE || Settings.Mode == LINE_MODE) SetLocalRef (0, 0, false); Crosshair.AttachedBox.State = STATE_FIRST; Crosshair.AttachedLine.State = STATE_FIRST; if (Mode == LINE_MODE && TEST_FLAG (AUTODRCFLAG, PCB)) { if (ClearFlagOnAllObjects (CONNECTEDFLAG | FOUNDFLAG, true)) { IncrementUndoSerialNumber (); Draw (); } } } Settings.Mode = Mode; crosshair_update_range(); recursing = false; notify_crosshair_change (true); } /*! * \brief Set route style. */ void SetRouteStyle (char *name) { char num[10]; STYLE_LOOP (PCB); { if (name && NSTRCMP (name, style->Name) == 0) { sprintf (num, "%d", n + 1); hid_actionl ("RouteStyle", num, NULL); break; } } END_LOOP; } void SetLocalRef (Coord X, Coord Y, bool Showing) { static MarkType old; static int count = 0; if (Showing) { notify_mark_change (false); if (count == 0) old = Marked; Marked.X = X; Marked.Y = Y; Marked.status = true; count++; notify_mark_change (true); } else if (count > 0) { notify_mark_change (false); count = 0; Marked = old; notify_mark_change (true); } } /* * Actions */ /* %start-doc actions SetupRouteStyle Sets the parameters of a route style. TODO: Doesn't currently update the GUI widgets. %end-doc */ static const char setup_route_style_syntax[] = N_("SetupRouteStyle(num, style_string)\n" "SetupRouteStyle(num, name, thickness, diameter, drill, keepaway, mask, units)\n"); static const char setup_route_style_help[] = N_("Setup the routing style using the given parameters. Parameters can be " "either a style string, or the values themselves."); static int setup_route_style_action (int argc, char **argv, Coord x, Coord y) { char *nstyle = ARG (0); char *name = ARG (1); char *thickness = ARG (2); char *diameter = ARG(3); char *drill = ARG(4); char *keepaway = ARG(5); char *mask_aperture = ARG(6); char *units = ARG(7); int n; bool absolute; n = atoi(nstyle); if (argc > 2) { /* we got the datams as parameters */ free(PCB->RouteStyle[n].Name); PCB->RouteStyle[n].Name = strdup(name); PCB->RouteStyle[n].Thick = GetValue(thickness, units, &absolute); PCB->RouteStyle[n].Diameter = GetValue(diameter, units, &absolute); PCB->RouteStyle[n].Hole = GetValue(drill, units, &absolute); PCB->RouteStyle[n].Keepaway = GetValue(keepaway, units, &absolute); PCB->RouteStyle[n].ViaMask = GetValue(mask_aperture, units, &absolute); } else { ParseRouteString(name, &PCB->RouteStyle[n], "mm"); } hid_action ("RouteStylesChanged"); return 0; } static HID_Action set_action_list[] = { {"SetupRouteStyle", NULL, setup_route_style_action, setup_route_style_help, setup_route_style_syntax} }; REGISTER_ACTIONS (set_action_list) pcb-4.2.2/src/lrealpath.c0000664000076400007640000001162713434555140012140 00000000000000/*! * \file src/lrealpath.c * * \brief Libiberty realpath. * * Like realpath, but more consistent behavior. * * Based on gdb_realpath from GDB. * * Copyright 2003 Free Software Foundation, Inc. * * This file is part of the libiberty library. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* @deftypefn Replacement {const char*} lrealpath (const char *@var{name}) Given a pointer to a string containing a pathname, returns a canonical version of the filename. Symlinks will be resolved, and ``.'' and ``..'' components will be simplified. The returned value will be allocated using @code{malloc}, or @code{NULL} will be returned on a memory allocation error. @end deftypefn */ #include "config.h" #include "lrealpath.h" #ifdef HAVE_LIMITS_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STRING_H #include #endif /* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */ #if defined(HAVE_CANONICALIZE_FILE_NAME) \ && defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME) extern char *canonicalize_file_name (const char *); #endif #if defined(HAVE_REALPATH) # if defined (PATH_MAX) # define REALPATH_LIMIT PATH_MAX # else # if defined (MAXPATHLEN) # define REALPATH_LIMIT MAXPATHLEN # endif # endif #else /* cygwin has realpath, so it won't get here. */ # if defined (_WIN32) # define WIN32_LEAN_AND_MEAN # include /* for GetFullPathName */ # endif #endif /*! * \brief A well-defined realpath () that is always compiled in. */ char * lrealpath (const char *filename) { /* Method 1: The system has a compile time upper bound on a filename path. Use that and realpath() to canonicalize the name. This is the most common case. Note that, if there isn't a compile time upper bound, you want to avoid realpath() at all costs. */ #if defined(REALPATH_LIMIT) { char buf[REALPATH_LIMIT]; const char *rp = realpath (filename, buf); if (rp == NULL) rp = filename; return strdup (rp); } /* REALPATH_LIMIT */ /* Method 2: The host system (i.e., GNU) has the function canonicalize_file_name() which malloc's a chunk of memory and returns that, use that. */ #elif defined(HAVE_CANONICALIZE_FILE_NAME) { char *rp = canonicalize_file_name (filename); if (rp == NULL) return strdup (filename); else return rp; } /* HAVE_CANONICALIZE_FILE_NAME */ /* Method 3: Now we're getting desperate! The system doesn't have a compile time buffer size and no alternative function. Query the OS, using pathconf(), for the buffer limit. Care is needed though, some systems do not limit PATH_MAX (return -1 for pathconf()) making it impossible to pass a correctly sized buffer to realpath() (it could always overflow). On those systems, we skip this. */ #elif defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) { /* Find out the max path size. */ long path_max = pathconf ("/", _PC_PATH_MAX); if (path_max > 0) { /* PATH_MAX is bounded. */ char *buf, *rp, *ret; buf = (char *) malloc (path_max); if (buf == NULL) return NULL; rp = realpath (filename, buf); ret = strdup (rp ? rp : filename); free (buf); return ret; } } /* HAVE_REALPATH && HAVE_UNISTD_H */ /* The MS Windows method. If we don't have realpath, we assume we don't have symlinks and just canonicalize to a Windows absolute path. GetFullPath converts ../ and ./ in relative paths to absolute paths, filling in current drive if one is not given or using the current directory of a specified drive (eg, "E:foo"). It also converts all forward slashes to back slashes. */ #elif defined (_WIN32) { char buf[MAX_PATH]; char* basename; DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename); if (len == 0 || len > MAX_PATH - 1) return strdup (filename); else { /* The file system is case-preserving but case-insensitive, Canonicalize to lowercase, using the codepage associated with the process locale. */ CharLowerBuff (buf, len); return strdup (buf); } } #else /* This system is a lost cause, just duplicate the filename. */ return strdup (filename); #endif } pcb-4.2.2/src/draw.c0000664000076400007640000012126213533277055011124 00000000000000/*! * \file src/draw.c * * \brief Drawing routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996, 2003, 2004 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include "hid_draw.h" /*#include "clip.h"*/ #include "compat.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "error.h" #include "mymem.h" #include "misc.h" #include "rotate.h" #include "rtree.h" #include "search.h" #include "select.h" #include "print.h" #ifdef HAVE_LIBDMALLOC #include #endif #undef NDEBUG #include #ifndef MAXINT #define MAXINT (((unsigned int)(~0))>>1) #endif #define SMALL_SMALL_TEXT_SIZE 0 #define SMALL_TEXT_SIZE 1 #define NORMAL_TEXT_SIZE 2 #define LARGE_TEXT_SIZE 3 #define N_TEXT_SIZES 4 /* --------------------------------------------------------------------------- * some local identifiers */ static BoxType Block = {MAXINT, MAXINT, -MAXINT, -MAXINT}; static int doing_pinout = 0; static bool doing_assy = false; static int current_layergroup; /* used by via_callback */ /* --------------------------------------------------------------------------- * some local prototypes */ static void DrawEverything (const BoxType *); static void DrawPPV (int group, const BoxType *); static void AddPart (void *); static void DrawEMark (ElementType *, Coord, Coord, bool); static void DrawRats (const BoxType *); static void set_object_color (AnyObjectType *obj, char *warn_color, char *selected_color, char *connected_color, char *found_color, char *normal_color) { char *color; if (warn_color != NULL && TEST_FLAG (WARNFLAG, obj)) color = warn_color; else if (selected_color != NULL && TEST_FLAG (SELECTEDFLAG, obj)) color = selected_color; else if (connected_color != NULL && TEST_FLAG (CONNECTEDFLAG, obj)) color = connected_color; else if (found_color != NULL && TEST_FLAG (FOUNDFLAG, obj)) color = found_color; else color = normal_color; gui->graphics->set_color (Output.fgGC, color); } static void set_layer_object_color (LayerType *layer, AnyObjectType *obj) { set_object_color (obj, NULL, layer->SelectedColor, PCB->ConnectedColor, PCB->FoundColor, layer->Color); } /*! * \brief Adds the update rect to the update region. */ static void AddPart (void *b) { BoxType *box = (BoxType *) b; Block.X1 = MIN (Block.X1, box->X1); Block.X2 = MAX (Block.X2, box->X2); Block.Y1 = MIN (Block.Y1, box->Y1); Block.Y2 = MAX (Block.Y2, box->Y2); } /*! * \brief Initiate the actual redrawing of the updated area. */ void Draw (void) { if (Block.X1 <= Block.X2 && Block.Y1 <= Block.Y2) gui->invalidate_lr (Block.X1, Block.X2, Block.Y1, Block.Y2); /* shrink the update block */ Block.X1 = Block.Y1 = MAXINT; Block.X2 = Block.Y2 = -MAXINT; } /*! * \brief Redraws all the data by the event handlers. */ void Redraw (void) { gui->invalidate_all (); } static void _draw_pv_name (PinType *pv) { BoxType box; bool vert; TextType text; if (!pv->Name || !pv->Name[0]) text.TextString = EMPTY (pv->Number); else text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pv->Number : pv->Name); vert = TEST_FLAG (EDGE2FLAG, pv); if (vert) { box.X1 = pv->X - pv->Thickness / 2 + Settings.PinoutTextOffsetY; box.Y1 = pv->Y - pv->DrillingHole / 2 - Settings.PinoutTextOffsetX; } else { box.X1 = pv->X + pv->DrillingHole / 2 + Settings.PinoutTextOffsetX; box.Y1 = pv->Y - pv->Thickness / 2 + Settings.PinoutTextOffsetY; } gui->graphics->set_color (Output.fgGC, PCB->PinNameColor); text.Flags = NoFlags (); /* Set font height to approx 56% of pin thickness */ text.Scale = 56 * pv->Thickness / FONT_CAPHEIGHT; text.X = box.X1; text.Y = box.Y1; text.Direction = vert ? 1 : 0; if (gui->gui) doing_pinout++; gui->graphics->draw_pcb_text (Output.fgGC, &text, 0); if (gui->gui) doing_pinout--; } static void _draw_pv (PinType *pv, bool draw_hole) { if (TEST_FLAG (THINDRAWFLAG, PCB)) gui->graphics->thindraw_pcb_pv (Output.fgGC, Output.fgGC, pv, draw_hole, false); else if (!ViaIsOnAnyVisibleLayer (pv)) gui->graphics->thindraw_pcb_pv (Output.fgGC, Output.fgGC, pv, false, false); else { gui->graphics->fill_pcb_pv (Output.fgGC, Output.bgGC, pv, draw_hole, false); if (gui->gui && VIA_IS_BURIED (pv) && !(TEST_FLAG (SELECTEDFLAG, pv) || TEST_FLAG (CONNECTEDFLAG, pv) || TEST_FLAG (FOUNDFLAG, pv))) { int w = (pv->Thickness - pv->DrillingHole) / 4; int r = pv->DrillingHole / 2 + w / 2; gui->graphics->set_line_cap (Output.fgGC, Square_Cap); gui->graphics->set_color (Output.fgGC, PCB->Data->Layer[pv->BuriedFrom].Color); gui->graphics->set_line_width (Output.fgGC, w); gui->graphics->draw_arc (Output.fgGC, pv->X, pv->Y, r, r, 270, 180); gui->graphics->set_color (Output.fgGC, PCB->Data->Layer[pv->BuriedTo].Color); gui->graphics->set_line_width (Output.fgGC, w); gui->graphics->draw_arc (Output.fgGC, pv->X, pv->Y, r, r, 90, 180); } } if ((!TEST_FLAG (HOLEFLAG, pv) && TEST_FLAG (DISPLAYNAMEFLAG, pv)) || doing_pinout) _draw_pv_name (pv); } static void draw_pin (PinType *pin, bool draw_hole) { if (doing_pinout) gui->graphics->set_color (Output.fgGC, PCB->PinColor); else set_object_color ((AnyObjectType *)pin, PCB->WarnColor, PCB->PinSelectedColor, PCB->ConnectedColor, PCB->FoundColor, PCB->PinColor); _draw_pv (pin, draw_hole); } static int pin_callback (const BoxType * b, void *cl) { draw_pin ((PinType *)b, false); return 1; } static void draw_via (PinType *via, bool draw_hole) { if (doing_pinout) gui->graphics->set_color (Output.fgGC, PCB->ViaColor); else set_object_color ((AnyObjectType *)via, PCB->WarnColor, PCB->ViaSelectedColor, PCB->ConnectedColor, PCB->FoundColor, PCB->ViaColor); _draw_pv (via, draw_hole); } static bool via_visible_on_layer_group (PinType *via) { if (current_layergroup == -1) return true; else return ViaIsOnLayerGroup (via, current_layergroup); } static int via_callback (const BoxType * b, void *cl) { PinType *via = (PinType *)b; if (via_visible_on_layer_group (via)) draw_via (via, false); return 1; } static void draw_pad_name (PadType *pad) { BoxType box; bool vert; TextType text; if (!pad->Name || !pad->Name[0]) text.TextString = EMPTY (pad->Number); else text.TextString = EMPTY (TEST_FLAG (SHOWNUMBERFLAG, PCB) ? pad->Number : pad->Name); /* should text be vertical ? */ vert = (pad->Point1.X == pad->Point2.X); if (vert) { box.X1 = pad->Point1.X - pad->Thickness / 2; box.Y1 = MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2; box.X1 += Settings.PinoutTextOffsetY; box.Y1 -= Settings.PinoutTextOffsetX; } else { box.X1 = MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2; box.Y1 = pad->Point1.Y - pad->Thickness / 2; box.X1 += Settings.PinoutTextOffsetX; box.Y1 += Settings.PinoutTextOffsetY; } gui->graphics->set_color (Output.fgGC, PCB->PinNameColor); text.Flags = NoFlags (); /* Set font height to approx 90% of pin thickness */ text.Scale = 90 * pad->Thickness / FONT_CAPHEIGHT; text.X = box.X1; text.Y = box.Y1; text.Direction = vert ? 1 : 0; gui->graphics->draw_pcb_text (Output.fgGC, &text, 0); } static void _draw_pad (hidGC gc, PadType *pad, bool clear, bool mask) { if (clear && !mask && pad->Clearance <= 0) return; if (TEST_FLAG (THINDRAWFLAG, PCB) || (clear && TEST_FLAG (THINDRAWPOLYFLAG, PCB))) gui->graphics->thindraw_pcb_pad (gc, pad, clear, mask); else gui->graphics->fill_pcb_pad (gc, pad, clear, mask); } static void draw_pad (PadType *pad) { if (doing_pinout) gui->graphics->set_color (Output.fgGC, PCB->PinColor); else set_object_color ((AnyObjectType *)pad, PCB->WarnColor, PCB->PinSelectedColor, PCB->ConnectedColor, PCB->FoundColor, FRONT (pad) ? PCB->PinColor : PCB->InvisibleObjectsColor); _draw_pad (Output.fgGC, pad, false, false); if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, pad)) draw_pad_name (pad); } static int pad_callback (const BoxType * b, void *cl) { PadType *pad = (PadType *) b; int *side = cl; if (ON_SIDE (pad, *side)) draw_pad (pad); return 1; } static void draw_element_name (ElementType *element) { if ((TEST_FLAG (HIDENAMESFLAG, PCB) && gui->gui) || TEST_FLAG (HIDENAMEFLAG, element)) return; if (doing_pinout || doing_assy) gui->graphics->set_color (Output.fgGC, PCB->ElementColor); else if (TEST_FLAG (SELECTEDFLAG, &ELEMENT_TEXT (PCB, element))) gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor); else if (FRONT (element)) gui->graphics->set_color (Output.fgGC, PCB->ElementColor); else gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor); gui->graphics->draw_pcb_text (Output.fgGC, &ELEMENT_TEXT (PCB, element), PCB->minSlk); } static int name_callback (const BoxType * b, void *cl) { TextType *text = (TextType *) b; ElementType *element = (ElementType *) text->Element; int *side = cl; if (TEST_FLAG (HIDENAMEFLAG, element)) return 0; if (ON_SIDE (element, *side)) draw_element_name (element); return 0; } static void draw_element_pins_and_pads (ElementType *element) { PAD_LOOP (element); { if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn) draw_pad (pad); } END_LOOP; PIN_LOOP (element); { draw_pin (pin, true); } END_LOOP; } static int EMark_callback (const BoxType * b, void *cl) { ElementType *element = (ElementType *) b; DrawEMark (element, element->MarkX, element->MarkY, !FRONT (element)); return 1; } typedef struct { int plated; bool drill_pair; Cardinal group_from; Cardinal group_to; } hole_info; static int hole_callback (const BoxType * b, void *cl) { hole_info his = {-1, false, 0, 0}; hole_info *hi = &his; PinType *pv = (PinType *) b; if (cl) hi = (hole_info *)cl; if (hi->drill_pair) { if (hi->group_from != 0 || hi->group_to != 0) { if (VIA_IS_BURIED (pv)) { if (hi->group_from == GetLayerGroupNumberByNumber (pv->BuriedFrom) && hi->group_to == GetLayerGroupNumberByNumber (pv->BuriedTo)) goto via_ok; } } else if (!VIA_IS_BURIED (pv)) goto via_ok; return 1; } via_ok: if ((hi->plated == 0 && !TEST_FLAG (HOLEFLAG, pv)) || (hi->plated == 1 && TEST_FLAG (HOLEFLAG, pv))) return 1; if (!via_visible_on_layer_group (pv)) return 1; if (TEST_FLAG (THINDRAWFLAG, PCB)) { if (!TEST_FLAG (HOLEFLAG, pv)) { gui->graphics->set_line_cap (Output.fgGC, Round_Cap); gui->graphics->set_line_width (Output.fgGC, 0); gui->graphics->draw_arc (Output.fgGC, pv->X, pv->Y, pv->DrillingHole / 2, pv->DrillingHole / 2, 0, 360); } } else if (ViaIsOnAnyVisibleLayer (pv)) gui->graphics->fill_circle (Output.bgGC, pv->X, pv->Y, pv->DrillingHole / 2); else { gui->graphics->set_line_cap (Output.fgGC, Round_Cap); gui->graphics->set_line_width (Output.fgGC, 0); gui->graphics->draw_arc (Output.fgGC, pv->X, pv->Y, pv->DrillingHole / 2, pv->DrillingHole / 2, 0, 360); } if (TEST_FLAG (HOLEFLAG, pv)) { set_object_color ((AnyObjectType *) pv, PCB->WarnColor, PCB->ViaSelectedColor, NULL, NULL, Settings.BlackColor); gui->graphics->set_line_cap (Output.fgGC, Round_Cap); gui->graphics->set_line_width (Output.fgGC, 0); gui->graphics->draw_arc (Output.fgGC, pv->X, pv->Y, pv->DrillingHole / 2, pv->DrillingHole / 2, 0, 360); } return 1; } void DrawHoles (bool draw_plated, bool draw_unplated, const BoxType *drawn_area, Cardinal g_from, Cardinal g_to) { hole_info hi = {-1, true, g_from, g_to}; if ( draw_plated && !draw_unplated) hi.plated = 1; if (!draw_plated && draw_unplated) hi.plated = 0; current_layergroup = -1; r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, &hi); r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, &hi); } static int line_callback (const BoxType * b, void *cl) { LayerType *layer = (LayerType *) cl; LineType *line = (LineType *) b; set_layer_object_color (layer, (AnyObjectType *) line); gui->graphics->draw_pcb_line (Output.fgGC, line); return 1; } static int rat_callback (const BoxType * b, void *cl) { RatType *rat = (RatType *)b; set_object_color ((AnyObjectType *) rat, NULL, PCB->RatSelectedColor, PCB->ConnectedColor, PCB->FoundColor, PCB->RatColor); if (Settings.RatThickness < 100) rat->Thickness = pixel_slop * Settings.RatThickness; /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */ if (TEST_FLAG(VIAFLAG, rat)) { int w = rat->Thickness; if (TEST_FLAG (THINDRAWFLAG, PCB)) gui->graphics->set_line_width (Output.fgGC, 0); else gui->graphics->set_line_width (Output.fgGC, w); gui->graphics->draw_arc (Output.fgGC, rat->Point1.X, rat->Point1.Y, w * 2, w * 2, 0, 360); } else gui->graphics->draw_pcb_line (Output.fgGC, (LineType *) rat); return 1; } static int arc_callback (const BoxType * b, void *cl) { LayerType *layer = (LayerType *) cl; ArcType *arc = (ArcType *) b; set_layer_object_color (layer, (AnyObjectType *) arc); gui->graphics->draw_pcb_arc (Output.fgGC, arc); return 1; } static void draw_element_package (ElementType *element) { /* set color and draw lines, arcs, text and pins */ if (doing_pinout || doing_assy) gui->graphics->set_color (Output.fgGC, PCB->ElementColor); else if (TEST_FLAG (SELECTEDFLAG, element)) gui->graphics->set_color (Output.fgGC, PCB->ElementSelectedColor); else if (FRONT (element)) gui->graphics->set_color (Output.fgGC, PCB->ElementColor); else gui->graphics->set_color (Output.fgGC, PCB->InvisibleObjectsColor); /* draw lines, arcs, text and pins */ ELEMENTLINE_LOOP (element); { gui->graphics->draw_pcb_line (Output.fgGC, line); } END_LOOP; ARC_LOOP (element); { gui->graphics->draw_pcb_arc (Output.fgGC, arc); } END_LOOP; } static int element_callback (const BoxType * b, void *cl) { ElementType *element = (ElementType *) b; int *side = cl; if (ON_SIDE (element, *side)) draw_element_package (element); return 1; } /*! * \brief Prints assembly drawing. */ void PrintAssembly (int side, const BoxType * drawn_area) { int side_group = GetLayerGroupNumberBySide (side); doing_assy = true; gui->graphics->set_draw_faded (Output.fgGC, 1); DrawLayerGroup (side_group, drawn_area); gui->graphics->set_draw_faded (Output.fgGC, 0); /* draw package */ DrawSilk (side, drawn_area); doing_assy = false; } /*! * \brief Initializes some identifiers for a new zoom factor and redraws * whole screen. */ static void DrawEverything (const BoxType *drawn_area) { int i, ngroups, side; int top_group, bottom_group; /* This is the list of layer groups we will draw. */ int do_group[MAX_GROUP]; /* This is the reverse of the order in which we draw them. */ int drawn_groups[MAX_GROUP]; int plated, unplated; bool paste_empty; int g_from, g_to; char s[22]; PCB->Data->SILKLAYER.Color = PCB->ElementColor; PCB->Data->BACKSILKLAYER.Color = PCB->InvisibleObjectsColor; memset (do_group, 0, sizeof (do_group)); for (ngroups = 0, i = 0; i < max_copper_layer; i++) { LayerType *l = LAYER_ON_STACK (i); int group = GetLayerGroupNumberByNumber (LayerStack[i]); if (l->On && !do_group[group]) { do_group[group] = 1; drawn_groups[ngroups++] = group; } } top_group = GetLayerGroupNumberBySide (TOP_SIDE); bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); /* * first draw all 'invisible' stuff */ if (!TEST_FLAG (CHECKPLANESFLAG, PCB) && gui->set_layer ("invisible", SL (INVISIBLE, 0), 0)) { side = SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE; if (PCB->ElementOn) { r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side); r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side); DrawLayer (&(PCB->Data->Layer[max_copper_layer + side]), drawn_area); } r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side); gui->end_layer (); } /* draw all layers in layerstack order */ for (i = ngroups - 1; i >= 0; i--) { int group = drawn_groups[i]; if (gui->set_layer (0, group, 0)) { DrawLayerGroup (group, drawn_area); gui->end_layer (); } } if (TEST_FLAG (CHECKPLANESFLAG, PCB) && gui->gui) return; /* Draw pins, pads, vias below silk */ if (gui->gui) DrawPPV (SWAP_IDENT ? bottom_group : top_group, drawn_area); else { CountHoles (&plated, &unplated, drawn_area); if (plated && gui->set_layer ("plated-drill", SL (PDRILL, 0), 0)) { DrawHoles (true, false, drawn_area, 0, 0); gui->end_layer (); } if (unplated && gui->set_layer ("unplated-drill", SL (UDRILL, 0), 0)) { DrawHoles (false, true, drawn_area, 0, 0); gui->end_layer (); } for (g_from = 0; g_from < (max_group - 1); g_from++) for (g_to = g_from+1 ; g_to < max_group; g_to++ ) { CountHolesEx (&plated, &unplated, drawn_area, g_from, g_to); sprintf (s, "plated-drill_%02d-%02d", g_from+1, g_to+1); if (plated && gui->set_layer (s, SL (PDRILL, 0), 0)) { DrawHoles (true, false, drawn_area, g_from, g_to); gui->end_layer (); } sprintf (s, "unplated-drill_%02d-%02d", g_from+1, g_to+1); if (unplated && gui->set_layer (s, SL (UDRILL, 0), 0)) { DrawHoles (false, true, drawn_area, g_from, g_to); gui->end_layer (); } } } /* Draw the solder mask if turned on */ if (gui->set_layer ("componentmask", SL (MASK, TOP), 0)) { DrawMask (TOP_SIDE, drawn_area); gui->end_layer (); } if (gui->set_layer ("soldermask", SL (MASK, BOTTOM), 0)) { DrawMask (BOTTOM_SIDE, drawn_area); gui->end_layer (); } if (gui->set_layer ("topsilk", SL (SILK, TOP), 0)) { DrawSilk (TOP_SIDE, drawn_area); gui->end_layer (); } if (gui->set_layer ("bottomsilk", SL (SILK, BOTTOM), 0)) { DrawSilk (BOTTOM_SIDE, drawn_area); gui->end_layer (); } if (gui->gui) { /* Draw element Marks */ if (PCB->PinOn) r_search (PCB->Data->element_tree, drawn_area, NULL, EMark_callback, NULL); /* Draw rat lines on top */ if (gui->set_layer ("rats", SL (RATS, 0), 0)) { DrawRats(drawn_area); gui->end_layer (); } } paste_empty = IsPasteEmpty (TOP_SIDE); if (gui->set_layer ("toppaste", SL (PASTE, TOP), paste_empty)) { DrawPaste (TOP_SIDE, drawn_area); gui->end_layer (); } paste_empty = IsPasteEmpty (BOTTOM_SIDE); if (gui->set_layer ("bottompaste", SL (PASTE, BOTTOM), paste_empty)) { DrawPaste (BOTTOM_SIDE, drawn_area); gui->end_layer (); } if (gui->set_layer ("topassembly", SL (ASSY, TOP), 0)) { PrintAssembly (TOP_SIDE, drawn_area); gui->end_layer (); } if (gui->set_layer ("bottomassembly", SL (ASSY, BOTTOM), 0)) { PrintAssembly (BOTTOM_SIDE, drawn_area); gui->end_layer (); } if (gui->set_layer ("fab", SL (FAB, 0), 0)) { PrintFab (Output.fgGC); gui->end_layer (); } } static void DrawEMark (ElementType *e, Coord X, Coord Y, bool invisible) { Coord mark_size = EMARK_SIZE; if (!PCB->InvisibleObjectsOn && invisible) return; if (e->Pin != NULL) { PinType *pin0 = e->Pin->data; if (TEST_FLAG (HOLEFLAG, pin0)) mark_size = MIN (mark_size, pin0->DrillingHole / 2); else mark_size = MIN (mark_size, pin0->Thickness / 2); } if (e->Pad != NULL) { PadType *pad0 = e->Pad->data; mark_size = MIN (mark_size, pad0->Thickness / 2); } gui->graphics->set_color (Output.fgGC, invisible ? PCB->InvisibleMarkColor : PCB->ElementColor); gui->graphics->set_line_cap (Output.fgGC, Trace_Cap); gui->graphics->set_line_width (Output.fgGC, 0); gui->graphics->draw_line (Output.fgGC, X - mark_size, Y, X, Y - mark_size); gui->graphics->draw_line (Output.fgGC, X + mark_size, Y, X, Y - mark_size); gui->graphics->draw_line (Output.fgGC, X - mark_size, Y, X, Y + mark_size); gui->graphics->draw_line (Output.fgGC, X + mark_size, Y, X, Y + mark_size); /* * If an element is locked, place a "L" on top of the "diamond". * This provides a nice visual indication that it is locked that * works even for color blind users. */ if (TEST_FLAG (LOCKFLAG, e) ) { gui->graphics->draw_line (Output.fgGC, X, Y, X + 2 * mark_size, Y); gui->graphics->draw_line (Output.fgGC, X, Y, X, Y - 4* mark_size); } } /*! * \brief Draws pins pads and vias - Always draws for non-gui HIDs, * otherwise drawing depends on PCB->PinOn and PCB->ViaOn. */ static void DrawPPV (int group, const BoxType *drawn_area) { int top_group = GetLayerGroupNumberBySide (TOP_SIDE); int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); int side; if (PCB->PinOn || !gui->gui) { /* draw element pins */ r_search (PCB->Data->pin_tree, drawn_area, NULL, pin_callback, NULL); /* draw element pads */ if (group == top_group) { side = TOP_SIDE; r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side); } if (group == bottom_group) { side = BOTTOM_SIDE; r_search (PCB->Data->pad_tree, drawn_area, NULL, pad_callback, &side); } } /* draw vias */ if (PCB->ViaOn || !gui->gui) { current_layergroup = (gui->gui)?(-1):group; /* Limit vias only for layer group */ r_search (PCB->Data->via_tree, drawn_area, NULL, via_callback, NULL); r_search (PCB->Data->via_tree, drawn_area, NULL, hole_callback, NULL); } if (PCB->PinOn || doing_assy) r_search (PCB->Data->pin_tree, drawn_area, NULL, hole_callback, NULL); } static int clearPin_callback (const BoxType * b, void *cl) { PinType *pin = (PinType *) b; bool do_clear=true; int side; if (TEST_FLAG (VIAFLAG, pin) && VIA_IS_BURIED (pin)) { side=*((int*)cl); if ((side == TOP_SIDE && pin->BuriedFrom != 0) || (side == BOTTOM_SIDE && pin->BuriedTo != GetMaxBottomLayer ())) do_clear = false; } if (do_clear) { if (TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG (THINDRAWPOLYFLAG, PCB)) gui->graphics->thindraw_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true); else gui->graphics->fill_pcb_pv (Output.pmGC, Output.pmGC, pin, false, true); } return 1; } struct poly_info { const BoxType *drawn_area; LayerType *layer; }; static int poly_callback (const BoxType * b, void *cl) { struct poly_info *i = cl; PolygonType *polygon = (PolygonType *)b; set_layer_object_color (i->layer, (AnyObjectType *) polygon); gui->graphics->draw_pcb_polygon (Output.fgGC, polygon, i->drawn_area); return 1; } static int clearPad_callback (const BoxType * b, void *cl) { PadType *pad = (PadType *) b; int *side = cl; if (ON_SIDE (pad, *side) && pad->Mask) _draw_pad (Output.pmGC, pad, true, true); return 1; } /*! * \brief Draws silk layer. */ void DrawSilk (int side, const BoxType * drawn_area) { #if 0 /* This code is used when you want to mask silk to avoid exposed pins and pads. We decided it was a bad idea to do this unconditionally, but the code remains. */ #endif #if 0 if (gui->poly_before) { gui->graphics->use_mask (HID_MASK_BEFORE); #endif DrawLayer (LAYER_PTR (max_copper_layer + side), drawn_area); /* draw package */ r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side); r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side); #if 0 } gui->graphics->use_mask (HID_MASK_CLEAR); r_search (PCB->Data->pin_tree, drawn_area, NULL, clearPin_callback, NULL); r_search (PCB->Data->via_tree, drawn_area, NULL, clearPin_callback, NULL); r_search (PCB->Data->pad_tree, drawn_area, NULL, clearPad_callback, &side); if (gui->poly_after) { gui->graphics->use_mask (HID_MASK_AFTER); DrawLayer (LAYER_PTR (max_copper_layer + layer), drawn_area); /* draw package */ r_search (PCB->Data->element_tree, drawn_area, NULL, element_callback, &side); r_search (PCB->Data->name_tree[NAME_INDEX (PCB)], drawn_area, NULL, name_callback, &side); } gui->graphics->use_mask (HID_MASK_OFF); #endif } static void DrawMaskBoardArea (int mask_type, const BoxType *drawn_area) { /* Skip the mask drawing if the GUI doesn't want this type */ if ((mask_type == HID_MASK_BEFORE && !gui->poly_before) || (mask_type == HID_MASK_AFTER && !gui->poly_after)) return; gui->graphics->use_mask (mask_type); gui->graphics->set_color (Output.fgGC, PCB->MaskColor); if (drawn_area == NULL) gui->graphics->fill_rect (Output.fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight); else gui->graphics->fill_rect (Output.fgGC, drawn_area->X1, drawn_area->Y1, drawn_area->X2, drawn_area->Y2); } /*! * \brief Draws solder mask layer - this will cover nearly everything. */ void DrawMask (int side, const BoxType *screen) { int thin = TEST_FLAG(THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB); if (thin) gui->graphics->set_color (Output.pmGC, PCB->MaskColor); else { DrawMaskBoardArea (HID_MASK_BEFORE, screen); gui->graphics->use_mask (HID_MASK_CLEAR); } r_search (PCB->Data->pin_tree, screen, NULL, clearPin_callback, NULL); r_search (PCB->Data->via_tree, screen, NULL, clearPin_callback, &side); r_search (PCB->Data->pad_tree, screen, NULL, clearPad_callback, &side); if (thin) gui->graphics->set_color (Output.pmGC, "erase"); else { DrawMaskBoardArea (HID_MASK_AFTER, screen); gui->graphics->use_mask (HID_MASK_OFF); } } /*! * \brief Draws solder paste layer for a given side of the board. */ void DrawPaste (int side, const BoxType *drawn_area) { gui->graphics->set_color (Output.fgGC, PCB->ElementColor); ALLPAD_LOOP (PCB->Data); { if (ON_SIDE (pad, side) && !TEST_FLAG (NOPASTEFLAG, pad) && pad->Mask > 0) { Coord save_thickness = pad->Thickness; Coord save_mask = pad->Mask; if (Settings.PasteAdjust != 0) { pad->Thickness = pad->Thickness + Settings.PasteAdjust; pad->Mask = pad->Mask + Settings.PasteAdjust; if (pad->Thickness < 0) { printf ("adjust thickness %8.4f -> %8.4f mask %8.4f -> %8.4f\n", COORD_TO_MM(save_thickness), COORD_TO_MM(pad->Thickness), COORD_TO_MM(save_mask), COORD_TO_MM(pad->Mask)); pad->Thickness = 0; } if (pad->Mask < 0) pad->Mask = 0; } if (pad->Mask < pad->Thickness) _draw_pad (Output.fgGC, pad, true, true); else _draw_pad (Output.fgGC, pad, false, false); pad->Thickness = save_thickness; pad->Mask = save_mask; } } ENDALL_LOOP; } static void DrawRats (const BoxType *drawn_area) { /* * XXX lesstif allows positive AND negative drawing in HID_MASK_CLEAR. * XXX gtk only allows negative drawing. * XXX using the mask here is to get rat transparency */ int can_mask = strcmp(gui->name, "lesstif") == 0; if (can_mask) gui->graphics->use_mask (HID_MASK_CLEAR); r_search (PCB->Data->rat_tree, drawn_area, NULL, rat_callback, NULL); if (can_mask) gui->graphics->use_mask (HID_MASK_OFF); } static int text_callback (const BoxType * b, void *cl) { LayerType *layer = cl; TextType *text = (TextType *)b; int min_silk_line; if (TEST_FLAG (SELECTEDFLAG, text)) gui->graphics->set_color (Output.fgGC, layer->SelectedColor); else gui->graphics->set_color (Output.fgGC, layer->Color); if (layer == &PCB->Data->SILKLAYER || layer == &PCB->Data->BACKSILKLAYER) min_silk_line = PCB->minSlk; else min_silk_line = PCB->minWid; gui->graphics->draw_pcb_text (Output.fgGC, text, min_silk_line); return 1; } void DrawLayer (LayerType *Layer, const BoxType *screen) { struct poly_info info = {screen, Layer}; /* print the non-clearing polys */ r_search (Layer->polygon_tree, screen, NULL, poly_callback, &info); if (TEST_FLAG (CHECKPLANESFLAG, PCB)) return; /* draw all visible lines this layer */ r_search (Layer->line_tree, screen, NULL, line_callback, Layer); /* draw the layer arcs on screen */ r_search (Layer->arc_tree, screen, NULL, arc_callback, Layer); /* draw the layer text on screen */ r_search (Layer->text_tree, screen, NULL, text_callback, Layer); /* We should check for gui->gui here, but it's kinda cool seeing the auto-outline magically disappear when you first add something to the "outline" layer. */ if (IsLayerEmpty (Layer) && (strcmp (Layer->Name, "outline") == 0 || strcmp (Layer->Name, "route") == 0)) { gui->graphics->set_color (Output.fgGC, Layer->Color); gui->graphics->set_line_width (Output.fgGC, PCB->minWid); gui->graphics->draw_rect (Output.fgGC, 0, 0, PCB->MaxWidth, PCB->MaxHeight); } } /*! * \brief Draws one layer group. * * If the exporter is not a GUI, also draws the pins / pads / vias in * this layer group. */ void DrawLayerGroup (int group, const BoxType *drawn_area) { int i, rv = 1; int layernum; LayerType *Layer; int n_entries = PCB->LayerGroups.Number[group]; Cardinal *layers = PCB->LayerGroups.Entries[group]; for (i = n_entries - 1; i >= 0; i--) { layernum = layers[i]; Layer = PCB->Data->Layer + layers[i]; if (strcmp (Layer->Name, "outline") == 0 || strcmp (Layer->Name, "route") == 0) rv = 0; if (layernum < max_copper_layer && Layer->On) DrawLayer (Layer, drawn_area); } if (n_entries > 1) rv = 1; if (rv && !gui->gui) DrawPPV (group, drawn_area); } static void GatherPVName (PinType *Ptr) { BoxType box; bool vert = TEST_FLAG (EDGE2FLAG, Ptr); if (vert) { box.X1 = Ptr->X - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY; box.Y1 = Ptr->Y - Ptr->DrillingHole / 2 - Settings.PinoutTextOffsetX; } else { box.X1 = Ptr->X + Ptr->DrillingHole / 2 + Settings.PinoutTextOffsetX; box.Y1 = Ptr->Y - Ptr->Thickness / 2 + Settings.PinoutTextOffsetY; } if (vert) { box.X2 = box.X1; box.Y2 = box.Y1; } else { box.X2 = box.X1; box.Y2 = box.Y1; } AddPart (&box); } static void GatherPadName (PadType *Pad) { BoxType box; bool vert; /* should text be vertical ? */ vert = (Pad->Point1.X == Pad->Point2.X); if (vert) { box.X1 = Pad->Point1.X - Pad->Thickness / 2; box.Y1 = MAX (Pad->Point1.Y, Pad->Point2.Y) + Pad->Thickness / 2; box.X1 += Settings.PinoutTextOffsetY; box.Y1 -= Settings.PinoutTextOffsetX; box.X2 = box.X1; box.Y2 = box.Y1; } else { box.X1 = MIN (Pad->Point1.X, Pad->Point2.X) - Pad->Thickness / 2; box.Y1 = Pad->Point1.Y - Pad->Thickness / 2; box.X1 += Settings.PinoutTextOffsetX; box.Y1 += Settings.PinoutTextOffsetY; box.X2 = box.X1; box.Y2 = box.Y1; } AddPart (&box); return; } /*! * \brief Draw a via object. */ void DrawVia (PinType *Via) { AddPart (Via); if (!TEST_FLAG (HOLEFLAG, Via) && TEST_FLAG (DISPLAYNAMEFLAG, Via)) DrawViaName (Via); } /*! * \brief Draws the name of a via. */ void DrawViaName (PinType *Via) { GatherPVName (Via); } /*! * \brief Draw a pin object. */ void DrawPin (PinType *Pin) { AddPart (Pin); if ((!TEST_FLAG (HOLEFLAG, Pin) && TEST_FLAG (DISPLAYNAMEFLAG, Pin)) || doing_pinout) DrawPinName (Pin); } /*! * \brief Draws the name of a pin. */ void DrawPinName (PinType *Pin) { GatherPVName (Pin); } /*! * \brief Draw a pad object. */ void DrawPad (PadType *Pad) { AddPart (Pad); if (doing_pinout || TEST_FLAG (DISPLAYNAMEFLAG, Pad)) DrawPadName (Pad); } /*! * \brief Draws the name of a pad. */ void DrawPadName (PadType *Pad) { GatherPadName (Pad); } /*! * \brief Draws a line on a layer. */ void DrawLine (LayerType *Layer, LineType *Line) { AddPart (Line); } /*! * \brief Draws a ratline. */ void DrawRat (RatType *Rat) { if (Settings.RatThickness < 100) Rat->Thickness = pixel_slop * Settings.RatThickness; /* rats.c set VIAFLAG if this rat goes to a containing poly: draw a donut */ if (TEST_FLAG(VIAFLAG, Rat)) { Coord w = Rat->Thickness; BoxType b; b.X1 = Rat->Point1.X - w * 2 - w / 2; b.X2 = Rat->Point1.X + w * 2 + w / 2; b.Y1 = Rat->Point1.Y - w * 2 - w / 2; b.Y2 = Rat->Point1.Y + w * 2 + w / 2; AddPart (&b); } else DrawLine (NULL, (LineType *)Rat); } /*! * \brief Draws an arc on a layer. */ void DrawArc (LayerType *Layer, ArcType *Arc) { AddPart (Arc); } /*! * \brief Draws a text on a layer. */ void DrawText (LayerType *Layer, TextType *Text) { AddPart (Text); } /*! * \brief Draws a polygon on a layer. */ void DrawPolygon (LayerType *Layer, PolygonType *Polygon) { AddPart (Polygon); } /*! * \brief Draws an element. */ void DrawElement (ElementType *Element) { DrawElementPackage (Element); DrawElementName (Element); DrawElementPinsAndPads (Element); } /*! * \brief Draws the name of an element. */ void DrawElementName (ElementType *Element) { if (TEST_FLAG (HIDENAMEFLAG, Element)) return; DrawText (NULL, &ELEMENT_TEXT (PCB, Element)); } /*! * \brief Draws the package of an element. */ void DrawElementPackage (ElementType *Element) { ELEMENTLINE_LOOP (Element); { DrawLine (NULL, line); } END_LOOP; ARC_LOOP (Element); { DrawArc (NULL, arc); } END_LOOP; } /*! * \brief Draw pins of an element. */ void DrawElementPinsAndPads (ElementType *Element) { PAD_LOOP (Element); { if (doing_pinout || doing_assy || FRONT (pad) || PCB->InvisibleObjectsOn) DrawPad (pad); } END_LOOP; PIN_LOOP (Element); { DrawPin (pin); } END_LOOP; } /*! * \brief Erase a via. */ void EraseVia (PinType *Via) { AddPart (Via); if (TEST_FLAG (DISPLAYNAMEFLAG, Via)) EraseViaName (Via); } /*! * \brief Erase a ratline. */ void EraseRat (RatType *Rat) { if (TEST_FLAG(VIAFLAG, Rat)) { Coord w = Rat->Thickness; BoxType b; b.X1 = Rat->Point1.X - w * 2 - w / 2; b.X2 = Rat->Point1.X + w * 2 + w / 2; b.Y1 = Rat->Point1.Y - w * 2 - w / 2; b.Y2 = Rat->Point1.Y + w * 2 + w / 2; AddPart (&b); } else EraseLine ((LineType *)Rat); } /*! * \brief Erase a via name. */ void EraseViaName (PinType *Via) { GatherPVName (Via); } /*! * \brief Erase a pad object. */ void ErasePad (PadType *Pad) { AddPart (Pad); if (TEST_FLAG (DISPLAYNAMEFLAG, Pad)) ErasePadName (Pad); } /*! * \brief Erase a pad name. */ void ErasePadName (PadType *Pad) { GatherPadName (Pad); } /*! * \brief Erase a pin object. */ void ErasePin (PinType *Pin) { AddPart (Pin); if (TEST_FLAG (DISPLAYNAMEFLAG, Pin)) ErasePinName (Pin); } /*! * \brief Erase a pin name. */ void ErasePinName (PinType *Pin) { GatherPVName (Pin); } /*! * \brief Erases a line on a layer. */ void EraseLine (LineType *Line) { AddPart (Line); } /*! * \brief Erases an arc on a layer. */ void EraseArc (ArcType *Arc) { if (!Arc->Thickness) return; AddPart (Arc); } /*! * \brief Erases a text on a layer. */ void EraseText (LayerType *Layer, TextType *Text) { /* r_delete_entry (Layer->text_tree, (BoxType *) Text); */ AddPart (Text); } /*! * \brief Erases a polygon on a layer. */ void ErasePolygon (PolygonType *Polygon) { AddPart (Polygon); } /*! * \brief Erases an element. */ void EraseElement (ElementType *Element) { ELEMENTLINE_LOOP (Element); { EraseLine (line); } END_LOOP; ARC_LOOP (Element); { EraseArc (arc); } END_LOOP; EraseElementName (Element); EraseElementPinsAndPads (Element); } /*! * \brief Erases all pins and pads of an element. */ void EraseElementPinsAndPads (ElementType *Element) { PIN_LOOP (Element); { ErasePin (pin); } END_LOOP; PAD_LOOP (Element); { ErasePad (pad); } END_LOOP; } /*! * \brief Erases the name of an element. */ void EraseElementName (ElementType *Element) { if (TEST_FLAG (HIDENAMEFLAG, Element)) return; EraseText (NULL, &ELEMENT_TEXT (PCB, Element));} void EraseObject (int type, void *lptr, void *ptr) { switch (type) { case VIA_TYPE: case PIN_TYPE: ErasePin ((PinType *) ptr); break; case TEXT_TYPE: EraseText ((LayerType *)lptr, (TextType *) ptr); break; case ELEMENTNAME_TYPE: EraseElementName ((ElementType *) ptr); break; case POLYGON_TYPE: ErasePolygon ((PolygonType *) ptr); break; case ELEMENT_TYPE: EraseElement ((ElementType *) ptr); break; case LINE_TYPE: case ELEMENTLINE_TYPE: case RATLINE_TYPE: EraseLine ((LineType *) ptr); break; case PAD_TYPE: ErasePad ((PadType *) ptr); break; case ARC_TYPE: case ELEMENTARC_TYPE: EraseArc ((ArcType *) ptr); break; default: Message ("hace: Internal ERROR, trying to erase an unknown type\n"); } } void DrawObject (int type, void *ptr1, void *ptr2) { switch (type) { case VIA_TYPE: if (PCB->ViaOn) DrawVia ((PinType *) ptr2); break; case LINE_TYPE: if (((LayerType *) ptr1)->On) DrawLine ((LayerType *) ptr1, (LineType *) ptr2); break; case ARC_TYPE: if (((LayerType *) ptr1)->On) DrawArc ((LayerType *) ptr1, (ArcType *) ptr2); break; case TEXT_TYPE: if (((LayerType *) ptr1)->On) DrawText ((LayerType *) ptr1, (TextType *) ptr2); break; case POLYGON_TYPE: if (((LayerType *) ptr1)->On) DrawPolygon ((LayerType *) ptr1, (PolygonType *) ptr2); break; case ELEMENT_TYPE: if (PCB->ElementOn && (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn)) DrawElement ((ElementType *) ptr2); break; case RATLINE_TYPE: if (PCB->RatOn) DrawRat ((RatType *) ptr2); break; case PIN_TYPE: if (PCB->PinOn) DrawPin ((PinType *) ptr2); break; case PAD_TYPE: if (PCB->PinOn) DrawPad ((PadType *) ptr2); break; case ELEMENTNAME_TYPE: if (PCB->ElementOn && (FRONT ((ElementType *) ptr2) || PCB->InvisibleObjectsOn)) DrawElementName ((ElementType *) ptr1); break; } } static void draw_element (ElementType *element) { draw_element_package (element); draw_element_name (element); draw_element_pins_and_pads (element); } /*! * \brief HID drawing callback. */ void hid_expose_callback (HID * hid, BoxType * region, void *item) { HID *old_gui = gui; gui = hid; Output.fgGC = gui->graphics->make_gc (); Output.bgGC = gui->graphics->make_gc (); Output.pmGC = gui->graphics->make_gc (); hid->graphics->set_color (Output.pmGC, "erase"); hid->graphics->set_color (Output.bgGC, "drill"); if (item) { doing_pinout = true; draw_element ((ElementType *)item); doing_pinout = false; } else DrawEverything (region); gui->graphics->destroy_gc (Output.fgGC); gui->graphics->destroy_gc (Output.bgGC); gui->graphics->destroy_gc (Output.pmGC); gui = old_gui; } pcb-4.2.2/src/rubberband.c0000664000076400007640000004161013533277055012273 00000000000000/*! * \file src/rubberband.c * * \brief Functions used by 'rubberband moves'. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef HAVE_STRING_H #include #endif #include #include #ifdef HAVE_UNISTD_H #include #endif #include "global.h" #include "create.h" #include "data.h" #include "error.h" #include "misc.h" #include "polygon.h" #include "rubberband.h" #include "rtree.h" #include "search.h" #ifdef HAVE_LIBDMALLOC #include #endif /* --------------------------------------------------------------------------- * some local prototypes */ static void CheckPadForRubberbandConnection (PadType *); static void CheckPinForRubberbandConnection (PinType *); static void CheckLinePointForRubberbandConnection (LayerType *, LineType *, PointType *, bool); static void CheckArcPointForRubberbandConnection (LayerType *Layer, ArcType *Arc, PointType *ArcPoint, bool Exact); static void CheckPolygonForRubberbandConnection (LayerType *, PolygonType *); static void CheckLinePointForRat (LayerType *, PointType *); static int rubber_callback (const BoxType * b, void *cl); struct rubber_info { Coord radius; Coord X, Y; LineType *line; BoxType box; LayerType *layer; }; static int rubber_callback (const BoxType * b, void *cl) { LineType *line = (LineType *) b; struct rubber_info *i = (struct rubber_info *) cl; double x, y, rad, dist1, dist2; Coord t; int touches = 0, n = 0 ; t = line->Thickness / 2; /* Check to see if the line is already in the rubberband list */ for (n = 0; n < Crosshair.AttachedObject.RubberbandN; n++) if (Crosshair.AttachedObject.Rubberband[n].Line == line) return 0; if (TEST_FLAG (LOCKFLAG, line)) return 0; if (line == i->line) return 0; /* * Check to see if the line touches a rectangular region. * To do this we need to look for the intersection of a circular * region and a rectangular region. */ if (i->radius == 0) { int found = 0; if (line->Point1.X + t >= i->box.X1 && line->Point1.X - t <= i->box.X2 && line->Point1.Y + t >= i->box.Y1 && line->Point1.Y - t <= i->box.Y2) { if (((i->box.X1 <= line->Point1.X) && (line->Point1.X <= i->box.X2)) || ((i->box.Y1 <= line->Point1.Y) && (line->Point1.Y <= i->box.Y2))) { /* * The circle is positioned such that the closest point * on the rectangular region boundary is not at a corner * of the rectangle. i.e. the shortest line from circle * center to rectangle intersects the rectangle at 90 * degrees. In this case our first test is sufficient */ touches = 1; } else { /* * Now we must check the distance from the center of the * circle to the corners of the rectangle since the * closest part of the rectangular region is the corner. */ x = MIN (abs (i->box.X1 - line->Point1.X), abs (i->box.X2 - line->Point1.X)); x *= x; y = MIN (abs (i->box.Y1 - line->Point1.Y), abs (i->box.Y2 - line->Point1.Y)); y *= y; x = x + y - (t * t); if (x <= 0) touches = 1; } if (touches) { CreateNewRubberbandEntry (i->layer, line, &line->Point1); found++; } } if (line->Point2.X + t >= i->box.X1 && line->Point2.X - t <= i->box.X2 && line->Point2.Y + t >= i->box.Y1 && line->Point2.Y - t <= i->box.Y2) { if (((i->box.X1 <= line->Point2.X) && (line->Point2.X <= i->box.X2)) || ((i->box.Y1 <= line->Point2.Y) && (line->Point2.Y <= i->box.Y2))) { touches = 1; } else { x = MIN (abs (i->box.X1 - line->Point2.X), abs (i->box.X2 - line->Point2.X)); x *= x; y = MIN (abs (i->box.Y1 - line->Point2.Y), abs (i->box.Y2 - line->Point2.Y)); y *= y; x = x + y - (t * t); if (x <= 0) touches = 1; } if (touches) { CreateNewRubberbandEntry (i->layer, line, &line->Point2); found++; } } return found; } /* circular search region */ if (i->radius < 0) rad = 0; /* require exact match */ else rad = SQUARE(i->radius + t); x = (i->X - line->Point1.X); x *= x; y = (i->Y - line->Point1.Y); y *= y; dist1 = x + y - rad; x = (i->X - line->Point2.X); x *= x; y = (i->Y - line->Point2.Y); y *= y; dist2 = x + y - rad; if (dist1 > 0 && dist2 > 0) return 0; #ifdef CLOSEST_ONLY /* keep this to remind me */ if (dist1 < dist2) CreateNewRubberbandEntry (i->layer, line, &line->Point1); else CreateNewRubberbandEntry (i->layer, line, &line->Point2); #else if (dist1 <= 0) CreateNewRubberbandEntry (i->layer, line, &line->Point1); if (dist2 <= 0) CreateNewRubberbandEntry (i->layer, line, &line->Point2); #endif return 1; } /*! * \brief Checks all visible lines which belong to the same layergroup * as the passed pad. * * If one of the endpoints of the line lays inside the pad, the line is * added to the 'rubberband' list. */ static void CheckPadForRubberbandConnection (PadType *Pad) { Coord half = Pad->Thickness / 2; Cardinal group; struct rubber_info info; info.box.X1 = MIN (Pad->Point1.X, Pad->Point2.X) - half; info.box.Y1 = MIN (Pad->Point1.Y, Pad->Point2.Y) - half; info.box.X2 = MAX (Pad->Point1.X, Pad->Point2.X) + half; info.box.Y2 = MAX (Pad->Point1.Y, Pad->Point2.Y) + half; info.radius = 0; info.line = NULL; group = GetLayerGroupNumberBySide ( TEST_FLAG (ONSOLDERFLAG, Pad) ? BOTTOM_SIDE : TOP_SIDE); /* check all visible layers in the same group */ GROUP_LOOP (PCB->Data, group); { /* check all visible lines of the group member */ info.layer = layer; if (info.layer->On) { r_search (info.layer->line_tree, &info.box, NULL, rubber_callback, &info); } } END_LOOP; } struct rinfo { int type; Cardinal group; PinType *pin; PadType *pad; PointType *point; }; static int rat_callback (const BoxType * box, void *cl) { RatType *rat = (RatType *) box; struct rinfo *i = (struct rinfo *) cl; switch (i->type) { case PIN_TYPE: if (rat->Point1.X == i->pin->X && rat->Point1.Y == i->pin->Y) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point1); else if (rat->Point2.X == i->pin->X && rat->Point2.Y == i->pin->Y) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point2); break; case PAD_TYPE: if (rat->Point1.X == i->pad->Point1.X && rat->Point1.Y == i->pad->Point1.Y && rat->group1 == i->group) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point1); else if (rat->Point2.X == i->pad->Point1.X && rat->Point2.Y == i->pad->Point1.Y && rat->group2 == i->group) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point2); else if (rat->Point1.X == i->pad->Point2.X && rat->Point1.Y == i->pad->Point2.Y && rat->group1 == i->group) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point1); else if (rat->Point2.X == i->pad->Point2.X && rat->Point2.Y == i->pad->Point2.Y && rat->group2 == i->group) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point2); else if (rat->Point1.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 && rat->Point1.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2 && rat->group1 == i->group) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point1); else if (rat->Point2.X == (i->pad->Point1.X + i->pad->Point2.X) / 2 && rat->Point2.Y == (i->pad->Point1.Y + i->pad->Point2.Y) / 2 && rat->group2 == i->group) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point2); break; case LINEPOINT_TYPE: if (rat->group1 == i->group && rat->Point1.X == i->point->X && rat->Point1.Y == i->point->Y) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point1); else if (rat->group2 == i->group && rat->Point2.X == i->point->X && rat->Point2.Y == i->point->Y) CreateNewRubberbandEntry (NULL, (LineType *) rat, &rat->Point2); break; default: Message ("hace: bad rubber-rat lookup callback\n"); } return 0; } static void CheckPadForRat (PadType *Pad) { struct rinfo info; info.group = GetLayerGroupNumberBySide ( TEST_FLAG (ONSOLDERFLAG, Pad) ? BOTTOM_SIDE : TOP_SIDE); info.pad = Pad; info.type = PAD_TYPE; r_search (PCB->Data->rat_tree, &Pad->BoundingBox, NULL, rat_callback, &info); } static void CheckPinForRat (PinType *Pin) { struct rinfo info; info.type = PIN_TYPE; info.pin = Pin; r_search (PCB->Data->rat_tree, &Pin->BoundingBox, NULL, rat_callback, &info); } static void CheckLinePointForRat (LayerType *Layer, PointType *Point) { struct rinfo info; info.group = GetLayerGroupNumberByPointer (Layer); info.point = Point; info.type = LINEPOINT_TYPE; r_search (PCB->Data->rat_tree, (BoxType *) Point, NULL, rat_callback, &info); } /*! * \brief Checks all visible lines. * * If one of the endpoints of the line lays inside the pin, the line is * added to the 'rubberband' list. * * Square pins are handled as if they were round. * * Speed and readability is more important then the few % of failures * that are immediately recognized. */ static void CheckPinForRubberbandConnection (PinType *Pin) { struct rubber_info info; Cardinal n; Coord t = Pin->Thickness / 2; info.box.X1 = Pin->X - t; info.box.X2 = Pin->X + t; info.box.Y1 = Pin->Y - t; info.box.Y2 = Pin->Y + t; info.line = NULL; if (TEST_FLAG (SQUAREFLAG, Pin)) info.radius = 0; else { info.radius = t; info.X = Pin->X; info.Y = Pin->Y; } for (n = 0; n < max_copper_layer; n++) { info.layer = LAYER_PTR (n); r_search (info.layer->line_tree, &info.box, NULL, rubber_callback, &info); } } /*! * \brief Checks all visible lines which belong to the same group as the * passed line. * * If one of the endpoints of the line lays * inside the passed line, * the scanned line is added to the 'rubberband' list. */ static void CheckLinePointForRubberbandConnection (LayerType *Layer, LineType *Line, PointType *LinePoint, bool Exact) { Cardinal group; struct rubber_info info; Coord t = Line->Thickness / 2; /* lookup layergroup and check all visible lines in this group */ info.radius = Exact ? -1 : MAX(Line->Thickness / 2, 1); info.box.X1 = LinePoint->X - t; info.box.X2 = LinePoint->X + t; info.box.Y1 = LinePoint->Y - t; info.box.Y2 = LinePoint->Y + t; info.line = Line; info.X = LinePoint->X; info.Y = LinePoint->Y; group = GetLayerGroupNumberByPointer (Layer); GROUP_LOOP (PCB->Data, group); { /* check all visible lines of the group member */ if (layer->On) { info.layer = layer; r_search (layer->line_tree, &info.box, NULL, rubber_callback, &info); } } END_LOOP; } /*! * \brief Checks all visible lines which belong to the same group as the * passed arc. * * If one of the endpoints of the line lays inside the passed arc, * the scanned line is added to the 'rubberband' list */ static void CheckArcPointForRubberbandConnection (LayerType *Layer, ArcType *Arc, PointType *ArcPoint, bool Exact) { Cardinal group; struct rubber_info info; Coord t = Arc->Thickness / 2; /* lookup layergroup and check all visible lines in this group */ info.radius = Exact ? -1 : MAX(Arc->Thickness / 2, 1); info.box.X1 = ArcPoint->X - t; info.box.X2 = ArcPoint->X + t; info.box.Y1 = ArcPoint->Y - t; info.box.Y2 = ArcPoint->Y + t; info.line = NULL; info.X = ArcPoint->X; info.Y = ArcPoint->Y; group = GetLayerGroupNumberByPointer (Layer); GROUP_LOOP (PCB->Data, group); { /* check all visible lines of the group member */ if (layer->On) { info.layer = layer; r_search (layer->line_tree, &info.box, NULL, rubber_callback, &info); } } END_LOOP; } /* --------------------------------------------------------------------------- * checks all visible lines which belong to the same group as the passed polygon. * If one of the endpoints of the line lays inside the passed polygon, * the scanned line is added to the 'rubberband' list. */ static void CheckPolygonForRubberbandConnection (LayerType *Layer, PolygonType *Polygon) { Cardinal group; /* lookup layergroup and check all visible lines in this group */ group = GetLayerGroupNumberByPointer (Layer); GROUP_LOOP (PCB->Data, group); { if (layer->On) { Coord thick; /* the following code just stupidly compares the endpoints * of the lines */ LINE_LOOP (layer); { if (TEST_FLAG (LOCKFLAG, line)) continue; if (TEST_FLAG (CLEARLINEFLAG, line)) continue; thick = (line->Thickness + 1) / 2; if (IsPointInPolygon (line->Point1.X, line->Point1.Y, thick, Polygon)) CreateNewRubberbandEntry (layer, line, &line->Point1); if (IsPointInPolygon (line->Point2.X, line->Point2.Y, thick, Polygon)) CreateNewRubberbandEntry (layer, line, &line->Point2); } END_LOOP; } } END_LOOP; } /*! * \brief Lookup all lines that are connected to an object and save the * data to 'Crosshair.AttachedObject.Rubberband'. * * Lookup is only done for visible layers. */ void LookupRubberbandLines (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { /* the function is only supported for some types * check all visible lines; * it is only necessary to check if one of the endpoints * is connected */ switch (Type) { case ELEMENT_TYPE: { ElementType *element = (ElementType *) Ptr1; /* square pins are handled as if they are round. Speed * and readability is more important then the few % * of failures that are immediately recognized */ PIN_LOOP (element); { CheckPinForRubberbandConnection (pin); } END_LOOP; PAD_LOOP (element); { CheckPadForRubberbandConnection (pad); } END_LOOP; break; } case LINE_TYPE: { LayerType *layer = (LayerType *) Ptr1; LineType *line = (LineType *) Ptr2; if (GetLayerNumber (PCB->Data, layer) < max_copper_layer) { CheckLinePointForRubberbandConnection (layer, line, &line->Point1, false); CheckLinePointForRubberbandConnection (layer, line, &line->Point2, false); } break; } case LINEPOINT_TYPE: if (GetLayerNumber (PCB->Data, (LayerType *) Ptr1) < max_copper_layer) CheckLinePointForRubberbandConnection ((LayerType *) Ptr1, (LineType *) Ptr2, (PointType *) Ptr3, true); break; case ARC_TYPE: { LayerType *layer = (LayerType *) Ptr1; ArcType *arc = (ArcType *) Ptr2; if (GetLayerNumber (PCB->Data, layer) < max_copper_layer) { CheckArcPointForRubberbandConnection (layer, arc, &arc->Point1, false); CheckArcPointForRubberbandConnection (layer, arc, &arc->Point2, false); } break; } case VIA_TYPE: CheckPinForRubberbandConnection ((PinType *) Ptr1); break; case POLYGON_TYPE: if (GetLayerNumber (PCB->Data, (LayerType *) Ptr1) < max_copper_layer) CheckPolygonForRubberbandConnection ((LayerType *) Ptr1, (PolygonType *) Ptr2); break; } } void LookupRatLines (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { switch (Type) { case ELEMENT_TYPE: { ElementType *element = (ElementType *) Ptr1; PIN_LOOP (element); { CheckPinForRat (pin); } END_LOOP; PAD_LOOP (element); { CheckPadForRat (pad); } END_LOOP; break; } case LINE_TYPE: { LayerType *layer = (LayerType *) Ptr1; LineType *line = (LineType *) Ptr2; CheckLinePointForRat (layer, &line->Point1); CheckLinePointForRat (layer, &line->Point2); break; } case LINEPOINT_TYPE: CheckLinePointForRat ((LayerType *) Ptr1, (PointType *) Ptr3); break; case VIA_TYPE: CheckPinForRat ((PinType *) Ptr1); break; } } pcb-4.2.2/src/create.h0000664000076400007640000000640313434555140011430 00000000000000/*! * \file src/create.h * * \brief Prototypes for create routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_CREATE_H #define PCB_CREATE_H #include "global.h" void CreateBeLenient (bool); DataType * CreateNewBuffer (void); void pcb_colors_from_settings (PCBType *); PCBType * CreateNewPCB (); int CreateNewPCBPost (PCBType *, int /* set defaults */); PinType * CreateNewVia (DataType *, Coord, Coord, Coord, Coord, Coord, Coord, char *, FlagType); PinType * CreateNewViaEx (DataType *, Coord, Coord, Coord, Coord, Coord, Coord, char *, FlagType, Cardinal buried_from, Cardinal buried_to); LineType * CreateDrawnLineOnLayer (LayerType *, Coord, Coord, Coord, Coord, Coord, Coord, FlagType); LineType * CreateNewLineOnLayer (LayerType *, Coord, Coord, Coord, Coord, Coord, Coord, FlagType); RatType * CreateNewRat (DataType *, Coord, Coord, Coord, Coord, Cardinal, Cardinal, Coord, FlagType); ArcType * CreateNewArcOnLayer (LayerType *, Coord, Coord, Coord, Coord, Angle, Angle, Coord, Coord, FlagType); PolygonType * CreateNewPolygonFromRectangle (LayerType *, Coord, Coord, Coord, Coord, FlagType); TextType * CreateNewText (LayerType *, FontType *, Coord, Coord, unsigned, int, char *, FlagType); PolygonType * CreateNewPolygon (LayerType *, FlagType); PointType * CreateNewPointInPolygon (PolygonType *, Coord, Coord); PolygonType * CreateNewHoleInPolygon (PolygonType *polygon); ElementType * CreateNewElement (DataType *, FontType *, FlagType, char *, char *, char *, Coord, Coord, BYTE, int, FlagType, bool); LineType * CreateNewLineInElement (ElementType *, Coord, Coord, Coord, Coord, Coord); ArcType * CreateNewArcInElement (ElementType *, Coord, Coord, Coord, Coord, Angle, Angle, Coord); PinType * CreateNewPin (ElementType *, Coord, Coord, Coord, Coord, Coord, Coord, char *, char *, FlagType); PadType * CreateNewPad (ElementType *, Coord, Coord, Coord, Coord, Coord, Coord, Coord, char *, char *, FlagType); LineType * CreateNewLineInSymbol (SymbolType *, Coord, Coord, Coord, Coord, Coord); void CreateDefaultFont (PCBType *); RubberbandType * CreateNewRubberbandEntry (LayerType *, LineType *, PointType *); LibraryMenuType * CreateNewNet (LibraryType *, char *, char *); LibraryEntryType * CreateNewConnection (LibraryMenuType *, char *); AttributeType * CreateNewAttribute (AttributeListType *list, char *name, char *value); #endif pcb-4.2.2/src/pcb-menu.res.in0000664000076400007640000004704513604156111012643 00000000000000# -*- c -*- # Note - pcb-menu.res is used to build pcb-menu.h # Note - parameters are sensitive to extra spaces around the commas Mouse = { Left = { Mode(Notify) up = Mode(Release) } Right = { { Mode(Save) Mode(Rotate) Mode(Notify) Mode(Release) Mode(Restore) } ctrl = Display(CycleCrosshair) } Middle = { Pan(1) up = Pan(0) ctrl = Pan(thumb,1) ctrl-up = Pan(thumb,0) } Up = Zoom(0.8) Down = Zoom(1.25) # If you want zoom to center, do this instead. #Up = { {Zoom(0.8) Center()} } #Down = { {Zoom(1.25) Center()} } } MainMenu = { {File {"About..." About()} {"Save layout" Save(Layout) m=S a={"Ctrl-S" "Ctrls"}} {"Save layout as..." Save(LayoutAs) m=A a={"Shift Ctrl-S" "Shift Ctrls"}} {"Revert" Load(Revert,none)} - {"Import Schematics" {"gschem" Import() } {"TinyCAD" ImportTinyCAD() } } {"Load layout" Load(Layout)} {"Load element data to paste-buffer" PasteBuffer(Clear) Load(ElementTobuffer)} {"Load layout data to paste-buffer" PasteBuffer(Clear) Load(LayoutTobuffer)} {"Load netlist file" Load(Netlist)} {"Load vendor resource file" LoadVendor()} {"Print layout..." Print()} {"Export layout..." Export()} {"Calibrate Printer..." PrintCalibrate()} - {"Save connection data of..." foreground=grey50 sensitive=false} {" a single element" GetXY(Click to set the element mark <>) Save(ElementConnections)} {" all elements" Save(AllConnections)} {" unused pins" Save(AllUnusedPins)} - {"Start new layout" New() a={"Ctrl-N" "Ctrln"}} - {"Quit Program" Quit() m=Q a={"Ctrl-Q" "Ctrlq"}} } {View {"Flip up/down" checked=flip_y SwapSides(V) a={"Tab" "Tab"}} {"Flip left/right" checked=flip_x SwapSides(H) a={"Shift-Tab" "ShiftTab"}} {"Spin 180°" SwapSides(R) a={"Ctrl-Tab" "CtrlTab"}} {"Swap Sides" SwapSides() a={"Ctrl-Shift-Tab" "Ctrl ShiftTab"}} {"Center cursor" Center() a={"C" "c"}} {"Show soldermask" checked=showmask Display(ToggleMask)} - {"Displayed element-name..." foreground=grey50 sensitive=false} {"Description" Display(Description) checked=elementname,1} {"Reference Designator" Display(NameOnPCB) checked=elementname,2} {"Value" Display(Value) checked=elementname,3} {"Lock Names" checked=locknames Display(ToggleLockNames)} {"Only Names" checked=onlynames Display(ToggleOnlyNames)} {"Hide Names" checked=hidenames Display(ToggleHideNames)} - {"Pinout shows number" checked=shownumber Display(ToggleName)} {"Open pinout menu" Display(Pinout) a={"Shift-D" "Shiftd"}} - {Zoom {"Zoom In 2X" Zoom(-2)} {"Zoom In 20%" Zoom(-1.2) m=Z a={"Z" "z"}} {"Zoom Out 20%" Zoom(+1.2) m=O a={"Shift-Z" "Shiftz"}} # If you want zoom to center, do this instead. #{"Zoom In 20%" Zoom(-1.2) Center() m=Z a={"Z" "z"}} #{"Zoom Out 20%" Zoom(+1.2) Center() m=O a={"Shift-Z" "Shiftz"}} {"Zoom Out 2X" Zoom(+2)} {"Zoom Max" Zoom() m=M a={"V" "v"}} {"Zoom Toggle" Zoom(Toggle) a={"`" "`"}} - {"Zoom to 0.1mil/px" Zoom(=0.1mil)} {"Zoom to 0.01mm/px" Zoom(=0.01mil)} {"Zoom to 1mil/px" Zoom(=1mil)} {"Zoom to 0.05mm/px" Zoom(=0.05mm)} {"Zoom to 2.5mil/px" Zoom(=2.5mil)} {"Zoom to 0.1mm/px" Zoom(=0.1mm)} {"Zoom to 10mil/px" Zoom(=10mil)} } {Grid {"mil" checked=grid_units_mil,1 SetUnits(mil)} {"mm" checked=grid_units_mm,1 SetUnits(mm)} {"Display grid" checked=drawgrid Display(Grid)} {"Realign grid" GetXY(Click to set the grid origin) Display(ToggleGrid)} {"No Grid" checked=grid,0 SetValue(Grid,1)} - { "0.1 mil" checked=gridsize,0.1mil SetUnits(mil) SetValue(Grid,0.1mil)} { "1 mil" checked=gridsize,1mil SetUnits(mil) SetValue(Grid,1mil)} { "5 mil" checked=gridsize,5mil SetUnits(mil) SetValue(Grid,5mil)} { "10 mil" checked=gridsize,10mil SetUnits(mil) SetValue(Grid,10mil)} { "25 mil" checked=gridsize,25mil SetUnits(mil) SetValue(Grid,25mil)} { "50 mil" checked=gridsize,50mil SetUnits(mil) SetValue(Grid,50mil)} {"100 mil" checked=gridsize,100mil SetUnits(mil) SetValue(Grid,100mil)} - {"0.01 mm" checked=gridsize,0.01mm SetUnits(mm) SetValue(Grid,0.01mm)} {"0.05 mm" checked=gridsize,0.05mm SetUnits(mm) SetValue(Grid,0.05mm)} {"0.1 mm" checked=gridsize,0.10mm SetUnits(mm) SetValue(Grid,0.1mm)} {"0.25 mm" checked=gridsize,0.25mm SetUnits(mm) SetValue(Grid,0.25mm)} {"0.5 mm" checked=gridsize,0.50mm SetUnits(mm) SetValue(Grid,0.5mm)} {"1 mm" checked=gridsize,1mm SetUnits(mm) SetValue(Grid,1mm)} - {"Grid -" SetValue(Grid,-) a={"Shift-G" "Shiftg"}} {"Grid +" SetValue(Grid,+) a={"G" "g"}} } - {"Shown Layers" @layerview - {"Edit Layer Groups" EditLayerGroups()} } {"Current Layer" @layerpick - {"Delete current layer" MoveLayer(c,-1)} {"Add new layer" MoveLayer(-1,c)} {"Move current layer up" MoveLayer(c,up)} {"Move current layer down" MoveLayer(c,down)} } } {Edit {"Undo last operation" Undo() a={"U" "u"}} {"Redo last undone operation" Redo() a={"Shift-R" "Shiftr"}} {"Clear undo-buffer" Undo(ClearList) a={"Shift-Ctrl-U" "Shift Ctrlu"}} - {"Cut selection to buffer" GetXY(Click to set the snap point for this buffer) PasteBuffer(Clear) PasteBuffer(AddSelected) RemoveSelected() Mode(PasteBuffer) a={"Ctrl-X" "Ctrlx"}} {"Copy selection to buffer" GetXY(Click to set the snap point for this buffer) PasteBuffer(Clear) PasteBuffer(AddSelected) Mode(PasteBuffer) a={"Ctrl-C" "Ctrlc"}} {"Paste buffer to layout" Mode(PasteBuffer) a={"Ctrl-V" "Ctrlv"}} - {"Unselect all" Unselect(All) a={"Shift-Alt-A" "Shift Alta"}} {"Select all visible" Select(All) a={"Alt-A" "Alta"}} - {"Edit Names..." foreground=grey50 sensitive=false} {" Change text on layout" ChangeName(Object) a={"N" "n"}} {" Edit name of layout" ChangeName(Layout)} {" Edit name of active layer" ChangeName(Layer)} {"Edit Attributes..." foreground=grey50 sensitive=false} {" Layout" Attributes(Layout)} {" CurrentLayer" Attributes(Layer)} {" Element" Attributes(Element)} - {"Board Sizes" AdjustSizes()} {"Route Styles" @routestyles - {"Edit..." AdjustStyle(0)} } - {"Via type" {"Through-hole" a={"Xtrl-Shift-P" "Ctrl Shiftp"} SetViaLayers(Object,th)} {"Buried from" a={"Xtrl-Shift-F" "Ctrl Shiftf"} SetViaLayers(Object,c,-)} {"Buried to" a={"Xtrl-Shift-T" "Ctrl Shiftt"} SetViaLayers(Object,-,c)} } } {Tools {"None" checked=nomode,1 Mode(None)} {"Via" checked=viamode,1 Mode(Via) a={"F1" "F1"}} {"Line" checked=linemode,1 Mode(Line) a={"F2" "F2"}} {"Arc" checked=arcmode,1 Mode(Arc) a={"F3" "F3"}} {"Text" checked=textmode,1 Mode(Text) a={"F4" "F4"}} {"Rectangle" checked=rectanglemode,1 Mode(Rectangle) a={"F5" "F5"}} {"Polygon" checked=polygonmode,1 Mode(Polygon) a={"F6" "F6"}} {"Polygon Hole" checked=polygonholemode,1 Mode(PolygonHole)} {"Buffer" checked=pastebuffermode,1 Mode(PasteBuffer) a={"F7" "F7"}} {"Remove" checked=removemode,1 Mode(Remove) a={"F8" "F8"}} {"Rotate" checked=rotatemode,1 Mode(Rotate) a={"F9" "F9"}} {"Thermal" checked=thermalmode,1 Mode(Thermal) a={"F10" "F10"}} {"Arrow" checked=arrowmode,1 Mode(Arrow) a={"F11" "F11"}} {"Insert Point" checked=insertpointmode,1 Mode(InsertPoint) a={"Insert" "Insert"}} {"Move" checked=movemode,1 Mode(Move)} {"Copy" checked=copymode,1 Mode(Copy)} {"Lock" checked=lockmode,1 Mode(Lock) a={"F12" "F12"}} {"Cancel" Mode(Cancel) a={"Esc" "Escape"}} - {"Command" Command() a={":" ":"}} } {Settings {"Layer groups" foreground=grey50 sensitive=false} {"Edit layer groupings" EditLayerGroups()} - {"'All-direction' lines" checked=alldirection Display(Toggle45Degree) a={"." "."}} {"Auto swap line start angle" checked=swapstartdir Display(ToggleStartDirection)} {"Orthogonal moves" checked=orthomove Display(ToggleOrthoMove)} {"Crosshair snaps to pins and pads" checked=snappin Display(ToggleSnapPin)} {"Crosshair shows DRC clearance" checked=showdrc Display(ToggleShowDRC)} {"Auto enforce DRC clearance" checked=autodrc Display(ToggleAutoDRC)} - {"Rubber band mode" checked=rubberband Display(ToggleRubberBandMode)} {"Require unique element names" checked=uniquename Display(ToggleUniqueNames)} {"Auto-zero delta measurements" checked=localref Display(ToggleLocalRef)} {"New lines, arcs clear polygons" checked=clearnew Display(ToggleClearLine)} {"New polygons are full ones" checked=newfullpoly Display(ToggleFullPoly)} {"Show autorouter trials" checked=liveroute Display(ToggleLiveRoute)} {"Thin draw" checked=thindraw Display(ToggleThindraw) a={"|" "|"}} {"Thin draw poly" checked=thindrawpoly Display(ToggleThindrawPoly) a={"Ctrl-Shift-P" "Ctrl Shiftp"}} {"Check polygons" checked=checkplanes Display(ToggleCheckPlanes)} - {"Pinout shows number" checked=shownumber Display(ToggleName)} {"Pins/Via show Name/Number" Display(PinOrPadName) a={"D" "d"}} {"Enable vendor drill mapping" ToggleVendor() checked=VendorMapOn} {"Import Settings" {"New elements added at..." foreground=grey50 sensitive=false} {" Center" Import(setnewpoint,center)} {" Mark" Import(setnewpoint,mark)} {" Crosshair" Import(setnewpoint)} - {"Set Dispersion" Import(setdisperse)} } } {Select {"Select all visible objects" Select(All)} {"Select all found objects" Select(Found)} {"Select all connected objects" Select(Connection)} - {"Unselect all objects" Unselect(All)} {"unselect all found objects" Unselect(Found)} {"unselect all connected objects" Unselect(Connection)} - {"Select by name" foreground=grey50 sensitive=false} {"All objects" Select(ObjectByName) active=have_regex} {"Elements" Select(ElementByName) active=have_regex} {"Pads" Select(PadByName) active=have_regex} {"Pins" Select(PinByName) active=have_regex} {"Text Objects" Select(TextByName) active=have_regex} {"Vias" Select(ViaByName) active=have_regex} - {"Auto-place selected elements" AutoPlaceSelected() a={"Ctrl-P" "Ctrlp"}} {"Disperse all elements" DisperseElements(All)} {"Move selected elements to other side" Flip(SelectedElements) a={"Shift-B" "Shiftb"}} {"Move selected to current layer" MoveToCurrentLayer(Selected) a={"Shift-M" "Shiftm"}} {"Delete selected objects" Delete(Selected) a={"Delete" "Delete"}} {"Convert selection to element" Select(Convert)} - {"Optimize selected rats" DeleteRats(SelectedRats) AddRats(SelectedRats)} {"Auto-route selected rats" AutoRoute(SelectedRats) a={"Alt-R" "Altr"}} {"Rip up selected auto-routed tracks" RipUp(Selected)} - {"Change size of selected objects" foreground=grey50 sensitive=false} {"Lines -10 mil" ChangeSize(SelectedLines,-10,mil) ChangeSize(SelectedArcs,-10,mil)} {"Lines +10 mil" ChangeSize(SelectedLines,+10,mil) ChangeSize(SelectedArcs,+10,mil)} {"Pads -10 mil" ChangeSize(SelectedPads,-10,mil)} {"Pads +10 mil" ChangeSize(SelectedPads,+10,mil)} {"Pins -10 mil" ChangeSize(SelectedPins,-10,mil)} {"Pins +10 mil" ChangeSize(SelectedPins,+10,mil)} {"Texts -10 mil" ChangeSize(SelectedTexts,-10,mil)} {"Texts +10 mil" ChangeSize(SelectedTexts,+10,mil)} {"Vias -10 mil" ChangeSize(SelectedVias,-10,mil)} {"Vias +10 mil" ChangeSize(SelectedVias,+10,mil)} - {"Change drilling hole of selected objects" foreground=grey50 sensitive=false} {"Vias -10 mil" ChangeDrillSize(SelectedVias,-10,mil)} {"Vias +10 mil" ChangeDrillSize(SelectedVias,+10,mil)} {"Pins -10 mil" ChangeDrillSize(SelectedPins,-10,mil)} {"Pins +10 mil" ChangeDrillSize(SelectedPins,+10,mil)} - {"Change square-flag of selected objects" foreground=grey50 sensitive=false} {"Elements" ChangeSquare(SelectedElements)} {"Pins" ChangeSquare(SelectedPins)} } {Buffer {"Copy selection to buffer" GetXY(Click to set the snap point for this buffer) PasteBuffer(Clear) PasteBuffer(AddSelected) Mode(PasteBuffer)} {"Cut selection to buffer" GetXY(Click to set the snap point for this buffer) PasteBuffer(Clear) PasteBuffer(AddSelected) RemoveSelected() Mode(PasteBuffer)} {"Paste buffer to layout" Mode(PasteBuffer)} - {"Rotate buffer 90 deg CCW" Mode(PasteBuffer) PasteBuffer(Rotate,1) a={"Shift-F7" "ShiftF7"}} {"Rotate buffer 90 deg CW" Mode(PasteBuffer) PasteBuffer(Rotate,3)} {"Arbitrarily Rotate Buffer" Mode(PasteBuffer) FreeRotateBuffer()} {"Mirror buffer (up/down)" Mode(PasteBuffer) PasteBuffer(Mirror)} {"Mirror buffer (left/right)" Mode(PasteBuffer) PasteBuffer(Rotate,1) PasteBuffer(Mirror) PasteBuffer(Rotate,3)} - {"Clear buffer" PasteBuffer(Clear)} {"Convert buffer to element" PasteBuffer(Convert)} {"Break buffer elements to pieces" PasteBuffer(Restore)} {"Save buffer elements to file" Save(PasteBuffer)} - {"Select current buffer" foreground=grey50 sensitive=false} {"#1" checked=buffer,1 PasteBuffer(1) a={"Shift-1" "Shift1"}} {"#2" checked=buffer,2 PasteBuffer(2) a={"Shift-2" "Shift2"}} {"#3" checked=buffer,3 PasteBuffer(3) a={"Shift-3" "Shift3"}} {"#4" checked=buffer,4 PasteBuffer(4) a={"Shift-4" "Shift4"}} {"#5" checked=buffer,5 PasteBuffer(5) a={"Shift-5" "Shift5"}} } {Connects {"Lookup connection to object" GetXY(Click on the object) Connection(Find) a={"Ctrl-F" "Ctrlf"}} {"Reset scanned pads/pins/vias" Connection(ResetPinsViasAndPads) Display(Redraw)} {"Reset scanned lines/polygons" Connection(ResetLinesAndPolygons) Display(Redraw)} {"Reset all connections" Connection(Reset) Display(Redraw) a={"Shift-F" "Shiftf"}} - {"Optimize rats-nest" Atomic(Save) DeleteRats(AllRats) Atomic(Restore) AddRats(AllRats) Atomic(Block) a={"O" "o"}} {"Erase rats-nest" DeleteRats(AllRats) a={"E" "e"}} {"Erase selected rats" DeleteRats(SelectedRats) a={"Shift-E" "Shifte"}} - {"Auto-route selected rats" AutoRoute(Selected)} {"Auto-route all rats" AutoRoute(AllRats)} {"Toporouter" Toporouter()} {"Rip up all auto-routed tracks" RipUp(All)} - {"Auto-Optimize" djopt(auto) a={"Shift-=" "Shift="}} {"Debumpify" djopt(debumpify) } {"Unjaggy" djopt(unjaggy) } {"Vianudge" djopt(vianudge) } {"Viatrim" djopt(viatrim) } {"Orthopull" djopt(orthopull) } {"SimpleOpts" djopt(simple) a={"=" "="}} {"Miter" djopt(miter) } {"Puller" a={"Y" "y"} Puller() } {"Global Puller" {"Selected" GlobalPuller(selected) } {"Found" GlobalPuller(found) } {"All" GlobalPuller() } } {"Only autorouted nets" OptAutoOnly() checked=optautoonly} - {"Design Rule Checker" DRC() DRCReview()} - {"Apply vendor drill mapping" ApplyVendor()} } {Info {"Generate object report" ReportObject() a={"Ctrl-R" "Ctrlr"}} {"Generate drill summary" Report(DrillReport)} {"Report found pins/pads" Report(FoundPins)} {"Report net length" Report(NetLength) a={"R" "r"}} {"Key Bindings" {"Remove" a={"Backspace" "BackSpace"} Delete(Selected) } {"Remove Connected" a={"Shift-Backspace" "ShiftBackSpace"} Atomic(Save) Connection(Reset) Atomic(Restore) Unselect(All) Atomic(Restore) Connection(Find) Atomic(Restore) Select(Connection) Atomic(Restore) RemoveSelected() Atomic(Restore) Connection(Reset) Atomic(Restore) Unselect(All) Atomic(Block) } {"Remove Connected" a={"Shift-Delete" "ShiftDelete"} Atomic(Save) Connection(Reset) Atomic(Restore) Unselect(All) Atomic(Restore) Connection(Find) Atomic(Restore) Select(Connection) Atomic(Restore) RemoveSelected() Atomic(Restore) Connection(Reset) Atomic(Restore) Unselect(All) Atomic(Block) } {"Set Same" a={"A" "a"} SetSame()} {"Flip Object" a={"B" "b"} Flip(Object)} {"Find Connections" a={"F" "f"} Connection(Reset) Connection(Find)} {"ToggleHideName Object" a={"H" "h"} ToggleHideName(Object)} {"ToggleHideName SelectedElement" a={"Shift-H" "Shifth"} ToggleHideName(SelectedElements)} {"ChangeHole Object" a={"Ctrl-H" "Ctrlh"} ChangeHole(Object)} {"ChangeJoin Object" a={"J" "j"} ChangeJoin(Object)} {"ChangeJoin SelectedObject" a={"Shift-J" "Shiftj"} ChangeJoin(SelectedObjects)} {"Clear Object +" a={"K" "k"} ChangeClearSize(Object,+)} {"Clear Object -" a={"Shift-K" "Shiftk"} ChangeClearSize(Object,-)} {"Clear Selected +" a={"Ctrl-K" "Ctrlk"} ChangeClearSize(SelectedObjects,+)} {"Clear Selected -" a={"Shift-Ctrl-K" "Shift Ctrlk"} ChangeClearSize(SelectedObjects,-)} {"Line Tool size +" a={"L" "l"} SetValue(LineSize,+)} {"Line Tool size -" a={"Shift-L" "Shiftl"} SetValue(LineSize,-)} {"Move Object to current layer" a={"M" "m"} MoveToCurrentLayer(Object)} {"MarkCrosshair" a={"Ctrl-M" "Ctrlm"} MarkCrosshair()} {"Select shortest rat" a={"Shift-N" "Shiftn"} AddRats(Close)} {"AddRats to selected pins" a={"Shift-O" "Shifto"} Atomic(Save) DeleteRats(AllRats) Atomic(Restore) AddRats(SelectedRats) Atomic(Block) } {"ChangeOctagon Object" a={"Ctrl-O" "Ctrlo"} ChangeOctagon(Object)} {"Polygon PreviousPoint" a={"P" "p"} Polygon(PreviousPoint)} {"Polygon Close" a={"Shift-P" "Shiftp"} Polygon(Close)} {"ChangeSquare Object" a={"Q" "q"} ChangeSquare(Object)} {"ChangeSize +" a={"S" "s"} ChangeSize(Object,+)} {"ChangeSize -" a={"Shift-S" "Shifts"} ChangeSize(Object,-)} {"ChangeDrill +5 mil" a={"Alt-S" "Alts"} ChangeDrillSize(Object,+5,mil)} {"ChangeDrill -5 mil" a={"Alt-Shift-S" "Alt Shifts"} ChangeDrillSize(Object,-5,mil)} {"Text Tool scale +10 mil" a={"T" "t"} SetValue(TextScale,+10,mil)} {"Text Tool scale -10 mil" a={"Shift-T" "Shiftt"} SetValue(TextScale,-10,mil)} {"Via Tool size +5 mil" a={"Shift-V" "Shiftv"} SetValue(ViaSize,+5,mil)} {"Via Tool size -5 mil" a={"Shift-Ctrl-V" "Shift Ctrlv"} SetValue(ViaSize,-5,mil)} {"Via Tool drill +5 mil" a={"Alt-V" "Altv"} SetValue(ViaDrillingHole,+5,mil)} {"Via Tool drill -5 mil" a={"Alt-Shift-V" "Alt Shiftv"} SetValue(ViaDrillingHole,-5,mil)} {"AddRats Selected" a={"Shift-W" "Shiftw"} AddRats(SelectedRats)} {"Add All Rats" a={"W" "w"} AddRats(AllRats)} {"Undo" a={"Alt-Z" "Altz"} Undo()} {"Cycle Clip" a={"/" "/"} Display(CycleClip)} {"Arrow" a={"Space" "space"} Mode(Arrow) checked=arrowmode,1} {"Temp Arrow ON" a={"[" "["} Mode(Save) Mode(Arrow) Mode(Notify)} {"Temp Arrow OFF" a={"]" "]"} Mode(Release) Mode(Restore)} {"Step Up" a={"Up" "Up"} Cursor(Warp,0,1,grid)} {"Step Down" a={"Down" "Down"} Cursor(Warp,0,-1,grid)} {"Step Left" a={"Left" "Left"} Cursor(Warp,-1,0,grid)} {"Step Right" a={"Right" "Right"} Cursor(Warp,1,0,grid)} {"Step +Up" a={"Up" "ShiftUp"} Cursor(Pan,0,50,view)} {"Step +Down" a={"Down" "ShiftDown"} Cursor(Pan,0,-50,view)} {"Step +Left" a={"Left" "ShiftLeft"} Cursor(Pan,-50,0,view)} {"Step +Right" a={"Right" "ShiftRight"} Cursor(Pan,50,0,view)} {'"Click"' a={"Enter" "Enter"} Mode(Notify) Mode(Release) } } } {Window {"Board Layout" DoWindows(Layout)} {"Library" DoWindows(Library)} {"Message Log" DoWindows(Log)} {"Netlist" DoWindows(Netlist)} {"Pinout" Display(Pinout) a={"Shift-D" "Shiftd"}} } } pcb-4.2.2/src/check_icon.data0000664000076400007640000000022611660653114012730 00000000000000#define check_icon_width 8 #define check_icon_height 8 static unsigned char check_icon_bits[] = { 0x80, 0xc0, 0x61, 0x31, 0x1b, 0x0f, 0x06, 0x00}; pcb-4.2.2/src/dbus.h0000664000076400007640000000174413434555140011125 00000000000000/*! * \file src/dbus.h * * \brief D-Bus IPC logic * * PCB, an interactive printed circuit board editor * * Copyright (C) 2006 University of Cambridge * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PCB_DBUS_H #define PCB_DBUS_H void pcb_dbus_setup (); void pcb_dbus_finish (); #endif /* !PCB_DBUS_H */ pcb-4.2.2/src/insert.h0000664000076400007640000000265713434555140011500 00000000000000/*! * \file src/insert.h * * \brief Prototypes for inserting points into objects. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_INSERT_H #define PCB_INSERT_H #include "global.h" #define INSERT_TYPES (POLYGON_TYPE | LINE_TYPE | RATLINE_TYPE) /* --------------------------------------------------------------------------- * prototypes */ void *InsertPointIntoObject (int, void *, void *, Cardinal *, Coord, Coord, bool, bool); PointType * AdjustInsertPoint (void); #endif pcb-4.2.2/src/undo.h0000664000076400007640000000574513533277055011150 00000000000000/*! * \file src/undo.h * * \brief Prototypes for undo routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_UNDO_H #define PCB_UNDO_H #include "global.h" #define DRAW_FLAGS (RATFLAG | SELECTEDFLAG | SQUAREFLAG | \ HIDENAMEFLAG | HOLEFLAG | OCTAGONFLAG | \ CONNECTEDFLAG | FOUNDFLAG | CLEARLINEFLAG) /* different layers */ int Undo (bool); int Redo (bool); int IncrementUndoSerialNumber (void); int SaveUndoSerialNumber (void); int RestoreUndoSerialNumber (void); int MergeUndoSerialRange (int, int); void ClearUndoList (bool); void MoveObjectToRemoveUndoList (int, void *, void *, void *); void AddObjectToRemovePointUndoList (int, void *, void *, Cardinal); void AddObjectToInsertPointUndoList (int, void *, void *, void *); void AddObjectToRemoveContourUndoList (int, LayerType *, PolygonType *); void AddObjectToInsertContourUndoList (int, LayerType *, PolygonType *); void AddObjectToMoveUndoList (int, void *, void *, void *, Coord, Coord); void AddObjectToChangeNameUndoList (int, void *, void *, void *, char *); void AddObjectToRotateUndoList (int, void *, void *, void *, Coord, Coord, BYTE); void AddObjectToCreateUndoList (int, void *, void *, void *); void AddObjectToMirrorUndoList (int, void *, void *, void *, Coord); void AddObjectToMoveToLayerUndoList (int, void *, void *, void *); void AddObjectToFlagUndoList (int, void *, void *, void *); void AddObjectToSizeUndoList (int, void *, void *, void *); void AddObjectTo2ndSizeUndoList (int, void *, void *, void *); void AddObjectToClearSizeUndoList (int, void *, void *, void *); void AddObjectToMaskSizeUndoList (int, void *, void *, void *); void AddObjectToChangeAnglesUndoList (int, void *, void *, void *); void AddObjectToClearPolyUndoList (int, void *, void *, void *, bool); void AddObjectToSetViaLayersUndoList (void *ptr1, void *ptr2, void *ptr3); void AddLayerChangeToUndoList (int, int); void AddNetlistLibToUndoList (LibraryType *); void LockUndo (void); void UnlockUndo (void); bool Undoing (void); #endif pcb-4.2.2/src/report.h0000664000076400007640000000241113434555140011473 00000000000000/*! * \file src/report.h * * \brief . * *
* * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_REPORT_H #define PCB_REPORT_H #include "global.h" #define REPORT_TYPES \ (VIA_TYPE | LINE_TYPE | TEXT_TYPE | POLYGON_TYPE | ELEMENT_TYPE | \ RATLINE_TYPE | PIN_TYPE | PAD_TYPE | ELEMENTNAME_TYPE | ARC_TYPE \ | POLYGONPOINT_TYPE | LINEPOINT_TYPE) #endif pcb-4.2.2/src/thermal.h0000664000076400007640000000310713434555140011617 00000000000000/*! * \file src/thermal.h * * \brief Prototypes for thermal routines. * * Thermals are normal lines on the layout. * * The only thing unique about them is that they have the USETHERMALFLAG * set so that they can be identified as thermals. * * It is handy for pcb to automatically make adjustments to the thermals * when the user performs certain operations, and the functions in * thermal.h help implement that. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996,2006 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_THERMAL_H #define PCB_THERMAL_H #include #include "global.h" #include "mymem.h" POLYAREA * ThermPoly (PCBType *, PinType *, Cardinal); #endif pcb-4.2.2/src/buffer.c0000664000076400007640000012433713533277055011446 00000000000000/*! * \file src/buffer.c * * \brief Functions used by paste- and move/copy buffer. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996, 2005 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "global.h" #include "buffer.h" #include "copy.h" #include "create.h" #include "crosshair.h" #include "data.h" #include "error.h" #include "flags.h" #include "mymem.h" #include "mirror.h" #include "misc.h" #include "parse_l.h" #include "polygon.h" #include "rats.h" #include "rotate.h" #include "remove.h" #include "rtree.h" #include "search.h" #include "select.h" #include "set.h" #ifdef HAVE_LIBDMALLOC #include #endif /* --------------------------------------------------------------------------- * some local prototypes */ static void *AddViaToBuffer (PinType *); static void *AddLineToBuffer (LayerType *, LineType *); static void *AddArcToBuffer (LayerType *, ArcType *); static void *AddRatToBuffer (RatType *); static void *AddTextToBuffer (LayerType *, TextType *); static void *AddPolygonToBuffer (LayerType *, PolygonType *); static void *AddElementToBuffer (ElementType *); static void *MoveViaToBuffer (PinType *); static void *MoveLineToBuffer (LayerType *, LineType *); static void *MoveArcToBuffer (LayerType *, ArcType *); static void *MoveRatToBuffer (RatType *); static void *MoveTextToBuffer (LayerType *, TextType *); static void *MovePolygonToBuffer (LayerType *, PolygonType *); static void *MoveElementToBuffer (ElementType *); static void SwapBuffer (BufferType *); /* --------------------------------------------------------------------------- * some local identifiers */ static DataType *Dest, *Source; static ObjectFunctionType AddBufferFunctions = { AddLineToBuffer, AddTextToBuffer, AddPolygonToBuffer, AddViaToBuffer, AddElementToBuffer, NULL, NULL, NULL, NULL, NULL, AddArcToBuffer, AddRatToBuffer }, MoveBufferFunctions = { MoveLineToBuffer, MoveTextToBuffer, MovePolygonToBuffer, MoveViaToBuffer, MoveElementToBuffer, NULL, NULL, NULL, NULL, NULL, MoveArcToBuffer, MoveRatToBuffer}; static int ExtraFlag = 0; /*! * \brief Copies a via to paste buffer. */ static void * AddViaToBuffer (PinType *Via) { return (CreateNewViaEx (Dest, Via->X, Via->Y, Via->Thickness, Via->Clearance, Via->Mask, Via->DrillingHole, Via->Name, MaskFlags (Via->Flags, NOCOPY_FLAGS | ExtraFlag), Via->BuriedFrom, Via->BuriedTo)); } /*! * \brief Copies a rat-line to paste buffer. */ static void * AddRatToBuffer (RatType *Rat) { return (CreateNewRat (Dest, Rat->Point1.X, Rat->Point1.Y, Rat->Point2.X, Rat->Point2.Y, Rat->group1, Rat->group2, Rat->Thickness, MaskFlags (Rat->Flags, NOCOPY_FLAGS | ExtraFlag))); } /*! * \brief Copies a line to buffer. */ static void * AddLineToBuffer (LayerType *Layer, LineType *Line) { LineType *line; LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)]; line = CreateNewLineOnLayer (layer, Line->Point1.X, Line->Point1.Y, Line->Point2.X, Line->Point2.Y, Line->Thickness, Line->Clearance, MaskFlags (Line->Flags, NOCOPY_FLAGS | ExtraFlag)); if (line && Line->Number) line->Number = strdup (Line->Number); return (line); } /*! * \brief Copies an arc to buffer. */ static void * AddArcToBuffer (LayerType *Layer, ArcType *Arc) { LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)]; return (CreateNewArcOnLayer (layer, Arc->X, Arc->Y, Arc->Width, Arc->Height, Arc->StartAngle, Arc->Delta, Arc->Thickness, Arc->Clearance, MaskFlags (Arc->Flags, NOCOPY_FLAGS | ExtraFlag))); } /*! * \brief Copies a text to buffer. */ static void * AddTextToBuffer (LayerType *Layer, TextType *Text) { LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)]; return (CreateNewText (layer, &PCB->Font, Text->X, Text->Y, Text->Direction, Text->Scale, Text->TextString, MaskFlags (Text->Flags, ExtraFlag))); } /*! * \brief Copies a polygon to buffer. */ static void * AddPolygonToBuffer (LayerType *Layer, PolygonType *Polygon) { LayerType *layer = &Dest->Layer[GetLayerNumber (Source, Layer)]; PolygonType *polygon; polygon = CreateNewPolygon (layer, Polygon->Flags); CopyPolygonLowLevel (polygon, Polygon); /* Update the polygon r-tree. Unlike similarly named functions for * other objects, CreateNewPolygon does not do this as it creates a * skeleton polygon object, which won't have correct bounds. */ if (!layer->polygon_tree) layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0); CLEAR_FLAG (NOCOPY_FLAGS | ExtraFlag, polygon); return (polygon); } /*! * \brief Copies a element to buffer. */ static void * AddElementToBuffer (ElementType *Element) { return CopyElementLowLevel (Dest, Element, false, 0, 0, NOCOPY_FLAGS | ExtraFlag); } /*! * \brief Moves a via to paste buffer without allocating memory for the * name. */ static void * MoveViaToBuffer (PinType *via) { RestoreToPolygon (Source, VIA_TYPE, via, via); r_delete_entry (Source->via_tree, (BoxType *) via); Source->Via = g_list_remove (Source->Via, via); Source->ViaN --; Dest->Via = g_list_append (Dest->Via, via); Dest->ViaN ++; CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, via); if (!Dest->via_tree) Dest->via_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Dest->via_tree, (BoxType *)via, 0); ClearFromPolygon (Dest, VIA_TYPE, via, via); return via; } /*! * \brief Moves a rat-line to paste buffer. */ static void * MoveRatToBuffer (RatType *rat) { r_delete_entry (Source->rat_tree, (BoxType *)rat); Source->Rat = g_list_remove (Source->Rat, rat); Source->RatN --; Dest->Rat = g_list_append (Dest->Rat, rat); Dest->RatN ++; CLEAR_FLAG (NOCOPY_FLAGS, rat); if (!Dest->rat_tree) Dest->rat_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Dest->rat_tree, (BoxType *)rat, 0); return rat; } /*! * \brief Moves a line to buffer. */ static void * MoveLineToBuffer (LayerType *layer, LineType *line) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; RestoreToPolygon (Source, LINE_TYPE, layer, line); r_delete_entry (layer->line_tree, (BoxType *)line); layer->Line = g_list_remove (layer->Line, line); layer->LineN --; lay->Line = g_list_append (lay->Line, line); lay->LineN ++; CLEAR_FLAG (NOCOPY_FLAGS, line); if (!lay->line_tree) lay->line_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->line_tree, (BoxType *)line, 0); ClearFromPolygon (Dest, LINE_TYPE, lay, line); return (line); } /*! * \brief Moves an arc to buffer. */ static void * MoveArcToBuffer (LayerType *layer, ArcType *arc) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; RestoreToPolygon (Source, ARC_TYPE, layer, arc); r_delete_entry (layer->arc_tree, (BoxType *)arc); layer->Arc = g_list_remove (layer->Arc, arc); layer->ArcN --; lay->Arc = g_list_append (lay->Arc, arc); lay->ArcN ++; CLEAR_FLAG (NOCOPY_FLAGS, arc); if (!lay->arc_tree) lay->arc_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->arc_tree, (BoxType *)arc, 0); ClearFromPolygon (Dest, ARC_TYPE, lay, arc); return (arc); } /*! * \brief Moves a text to buffer without allocating memory for the name. */ static void * MoveTextToBuffer (LayerType *layer, TextType *text) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; r_delete_entry (layer->text_tree, (BoxType *)text); RestoreToPolygon (Source, TEXT_TYPE, layer, text); layer->Text = g_list_remove (layer->Text, text); layer->TextN --; lay->Text = g_list_append (lay->Text, text); lay->TextN ++; if (!lay->text_tree) lay->text_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->text_tree, (BoxType *)text, 0); ClearFromPolygon (Dest, TEXT_TYPE, lay, text); return (text); } /*! * \brief Moves a polygon to buffer. * * Doesn't allocate memory for the points. */ static void * MovePolygonToBuffer (LayerType *layer, PolygonType *polygon) { LayerType *lay = &Dest->Layer[GetLayerNumber (Source, layer)]; r_delete_entry (layer->polygon_tree, (BoxType *)polygon); layer->Polygon = g_list_remove (layer->Polygon, polygon); layer->PolygonN --; lay->Polygon = g_list_append (lay->Polygon, polygon); lay->PolygonN ++; CLEAR_FLAG (NOCOPY_FLAGS, polygon); if (!lay->polygon_tree) lay->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (lay->polygon_tree, (BoxType *)polygon, 0); return (polygon); } /*! * \brief Moves a element to buffer without allocating memory for * pins/names. */ static void * MoveElementToBuffer (ElementType *element) { /* * Delete the element from the source (remove it from trees, * restore to polygons) */ r_delete_element (Source, element); Source->Element = g_list_remove (Source->Element, element); Source->ElementN --; Dest->Element = g_list_append (Dest->Element, element); Dest->ElementN ++; PIN_LOOP (element); { RestoreToPolygon(Source, PIN_TYPE, element, pin); CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pin); } END_LOOP; PAD_LOOP (element); { RestoreToPolygon(Source, PAD_TYPE, element, pad); CLEAR_FLAG (WARNFLAG | NOCOPY_FLAGS, pad); } END_LOOP; SetElementBoundingBox (Dest, element, &PCB->Font); /* * Now clear the from the polygons in the destination */ PIN_LOOP (element); { ClearFromPolygon (Dest, PIN_TYPE, element, pin); } END_LOOP; PAD_LOOP (element); { ClearFromPolygon (Dest, PAD_TYPE, element, pad); } END_LOOP; return element; } /*! * \brief Calculates the bounding box of the buffer. */ void SetBufferBoundingBox (BufferType *Buffer) { BoxType *box = GetDataBoundingBox (Buffer->Data); if (box) Buffer->BoundingBox = *box; } /*! * \brief Clears the contents of the paste buffer. */ void ClearBuffer (BufferType *Buffer) { if (Buffer && Buffer->Data) { FreeDataMemory (Buffer->Data); Buffer->Data->pcb = PCB; } } /*! * \brief Copies all selected and visible objects to the paste buffer. * * \return true if any objects have been removed. */ void AddSelectedToBuffer (BufferType *Buffer, Coord X, Coord Y, bool LeaveSelected) { /* switch crosshair off because adding objects to the pastebuffer * may change the 'valid' area for the cursor */ if (!LeaveSelected) ExtraFlag = SELECTEDFLAG; notify_crosshair_change (false); Source = PCB->Data; Dest = Buffer->Data; SelectedOperation (&AddBufferFunctions, false, ALL_TYPES); /* set origin to passed or current position */ if (X || Y) { Buffer->X = X; Buffer->Y = Y; } else { Buffer->X = Crosshair.X; Buffer->Y = Crosshair.Y; } notify_crosshair_change (true); ExtraFlag = 0; } /*! * \brief Loads element data from file/library into buffer. * * Parse the file with disabled 'PCB mode' (see parser). * * \return false on error, if successful, update some other stuff and * reposition the pastebuffer. */ bool LoadElementToBuffer (BufferType *Buffer, char *Name, bool FromFile) { ElementType *element; ClearBuffer (Buffer); if (FromFile) { if (!ParseElementFile (Buffer->Data, Name)) { if (Settings.ShowBottomSide) SwapBuffer (Buffer); SetBufferBoundingBox (Buffer); if (Buffer->Data->ElementN) { element = Buffer->Data->Element->data; Buffer->X = element->MarkX; Buffer->Y = element->MarkY; } else { Buffer->X = 0; Buffer->Y = 0; } return (true); } } else { if (!ParseLibraryEntry (Buffer->Data, Name) && Buffer->Data->ElementN != 0) { element = Buffer->Data->Element->data; /* always add elements using top-side coordinates */ if (Settings.ShowBottomSide) MirrorElementCoordinates (Buffer->Data, element, 0); SetElementBoundingBox (Buffer->Data, element, &PCB->Font); /* set buffer offset to 'mark' position */ Buffer->X = element->MarkX; Buffer->Y = element->MarkY; SetBufferBoundingBox (Buffer); return (true); } } /* release memory which might have been acquired */ ClearBuffer (Buffer); return (false); } typedef struct { char *footprint; int footprint_allocated; int menu_idx; int entry_idx; } FootprintHashEntry; static FootprintHashEntry *footprint_hash = 0; int footprint_hash_size = 0; void clear_footprint_hash () { int i; if (!footprint_hash) return; for (i=0; ifootprint, b->footprint); if (i == 0) i = a->menu_idx - b->menu_idx; if (i == 0) i = a->entry_idx - b->entry_idx; return i; } void make_footprint_hash () { int i, j; char *fp; int num_entries = 0; clear_footprint_hash (); for (i=0; i 1) { i = (min+max)/2; c = strcmp (footprint, footprint_hash[i].footprint); if (c < 0) max = i; else if (c > 0) min = i; else { /* We want to return the first match, not just any match. */ while (i > 0 && strcmp (footprint, footprint_hash[i-1].footprint) == 0) i--; return & footprint_hash[i]; } } return NULL; } /*! * \brief . * * \return zero on success, non-zero on error. */ int LoadFootprintByName (BufferType *Buffer, char *Footprint) { int i; FootprintHashEntry *fpe; LibraryMenuType *menu; LibraryEntryType *entry; char *with_fp = NULL; if (!footprint_hash) make_footprint_hash (); fpe = search_footprint_hash (Footprint); if (!fpe) { with_fp = Concat (Footprint, ".fp", NULL); fpe = search_footprint_hash (with_fp); if (fpe) Footprint = with_fp; } if (!fpe) { Message(_("Unable to load footprint %s\n"), Footprint); return 1; } menu = & Library.Menu[fpe->menu_idx]; entry = & menu->Entry[fpe->entry_idx]; if (entry->Template == (char *) -1) { i = LoadElementToBuffer (Buffer, entry->AllocatedMemory, true); if (with_fp) free (with_fp); return i ? 0 : 1; } else { char *args; args = Concat("'", EMPTY (entry->Template), "' '", EMPTY (entry->Value), "' '", EMPTY (entry->Package), "'", NULL); i = LoadElementToBuffer (Buffer, args, false); free (args); if (with_fp) free (with_fp); return i ? 0 : 1; } #ifdef DEBUG { int j; printf("Library path: %s\n", Settings.LibraryPath); printf("Library tree: %s\n", Settings.LibraryTree); printf("Library:\n"); for (i=0; iData->ElementN == 0) { Message(_("Footprint %s contains no elements"), name); return 1; } if (PASTEBUFFER->Data->ElementN > 1) { Message(_("Footprint %s contains multiple elements"), name); return 1; } e = PASTEBUFFER->Data->Element->data; if (e->Name[0].TextString) free (e->Name[0].TextString); e->Name[0].TextString = strdup (name); if (e->Name[1].TextString) free (e->Name[1].TextString); e->Name[1].TextString = refdes ? strdup (refdes) : 0; if (e->Name[2].TextString) free (e->Name[2].TextString); e->Name[2].TextString = value ? strdup (value) : 0; return 0; } /*! * \brief Break buffer element into pieces. */ bool SmashBufferElement (BufferType *Buffer) { ElementType *element; Cardinal group; LayerType *top_layer, *bottom_layer; if (Buffer->Data->ElementN != 1) { Message (_("Error! Buffer doesn't contain a single element\n")); return (false); } /* * At this point the buffer should contain just a single element. * Now we detach the single element from the buffer and then clear the * buffer, ready to receive the smashed elements. As a result of detaching * it the single element is orphaned from the buffer and thus will not be * free()'d by FreeDataMemory (called via ClearBuffer). This leaves it * around for us to smash bits off it. It then becomes our responsibility, * however, to free the single element when we're finished with it. */ element = Buffer->Data->Element->data; Buffer->Data->Element = NULL; Buffer->Data->ElementN = 0; ClearBuffer (Buffer); ELEMENTLINE_LOOP (element); { CreateNewLineOnLayer (&Buffer->Data->SILKLAYER, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, line->Thickness, 0, NoFlags ()); if (line) line->Number = STRDUP (NAMEONPCB_NAME (element)); } END_LOOP; ARC_LOOP (element); { CreateNewArcOnLayer (&Buffer->Data->SILKLAYER, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta, arc->Thickness, 0, NoFlags ()); } END_LOOP; PIN_LOOP (element); { FlagType f = NoFlags (); AddFlags (f, VIAFLAG); if (TEST_FLAG (HOLEFLAG, pin)) AddFlags (f, HOLEFLAG); CreateNewVia (Buffer->Data, pin->X, pin->Y, pin->Thickness, pin->Clearance, pin->Mask, pin->DrillingHole, pin->Number, f); } END_LOOP; group = GetLayerGroupNumberBySide (SWAP_IDENT ? BOTTOM_SIDE : TOP_SIDE); top_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]]; group = GetLayerGroupNumberBySide (SWAP_IDENT ? TOP_SIDE : BOTTOM_SIDE); bottom_layer = &Buffer->Data->Layer[PCB->LayerGroups.Entries[group][0]]; PAD_LOOP (element); { LineType *line; line = CreateNewLineOnLayer (TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_layer : top_layer, pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y, pad->Thickness, pad->Clearance, NoFlags ()); if (line) line->Number = STRDUP (pad->Number); } END_LOOP; FreeElementMemory (element); g_slice_free (ElementType, element); return (true); } /*! * \brief See if a polygon is a rectangle. * * If so, canonicalize it. */ static int polygon_is_rectangle (PolygonType *poly) { int i, best; PointType temp[4]; if (poly->PointN != 4 || poly->HoleIndexN != 0) return 0; best = 0; for (i=1; i<4; i++) if (poly->Points[i].X < poly->Points[best].X || poly->Points[i].Y < poly->Points[best].Y) best = i; for (i=0; i<4; i++) temp[i] = poly->Points[(i+best)%4]; if (temp[0].X == temp[1].X) memcpy (poly->Points, temp, sizeof(temp)); else { /* reverse them */ poly->Points[0] = temp[0]; poly->Points[1] = temp[3]; poly->Points[2] = temp[2]; poly->Points[3] = temp[1]; } if (poly->Points[0].X == poly->Points[1].X && poly->Points[1].Y == poly->Points[2].Y && poly->Points[2].X == poly->Points[3].X && poly->Points[3].Y == poly->Points[0].Y) return 1; return 0; } /*! * \brief Convert buffer contents into an element. */ bool ConvertBufferToElement (BufferType *Buffer) { ElementType *Element; Cardinal group; Cardinal pin_n = 1; bool hasParts = false, crooked = false; int onsolder; bool warned = false; if (Buffer->Data->pcb == 0) Buffer->Data->pcb = PCB; Element = CreateNewElement (PCB->Data, &PCB->Font, NoFlags (), NULL, NULL, NULL, PASTEBUFFER->X, PASTEBUFFER->Y, 0, 100, MakeFlags (SWAP_IDENT ? ONSOLDERFLAG : NOFLAG), false); if (!Element) return (false); VIA_LOOP (Buffer->Data); { char num[8]; if (via->Mask < via->Thickness) via->Mask = via->Thickness + 2 * MASKFRAME; if (via->Name) CreateNewPin (Element, via->X, via->Y, via->Thickness, via->Clearance, via->Mask, via->DrillingHole, NULL, via->Name, MaskFlags (via->Flags, VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG | WARNFLAG)); else { sprintf (num, "%d", pin_n++); CreateNewPin (Element, via->X, via->Y, via->Thickness, via->Clearance, via->Mask, via->DrillingHole, NULL, num, MaskFlags (via->Flags, VIAFLAG | NOCOPY_FLAGS | SELECTEDFLAG | WARNFLAG)); } hasParts = true; } END_LOOP; for (onsolder = 0; onsolder < 2; onsolder ++) { int side; int onsolderflag; if ((!onsolder) == (!SWAP_IDENT)) { side = TOP_SIDE; onsolderflag = NOFLAG; } else { side = BOTTOM_SIDE; onsolderflag = ONSOLDERFLAG; } #define MAYBE_WARN() \ if (onsolder && !hasParts && !warned) \ { \ warned = true; \ Message \ (_("Warning: All of the pads are on the opposite\n" \ "side from the component - that's probably not what\n" \ "you wanted\n")); \ } \ /* get the component-side SM pads */ group = GetLayerGroupNumberBySide (side); GROUP_LOOP (Buffer->Data, group); { char num[8]; LINE_LOOP (layer); { sprintf (num, "%d", pin_n++); CreateNewPad (Element, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, line->Thickness, line->Clearance, line->Thickness + line->Clearance, NULL, line->Number ? line->Number : num, MakeFlags (onsolderflag)); MAYBE_WARN(); hasParts = true; } END_LOOP; POLYGON_LOOP (layer); { Coord x1, y1, x2, y2, w, h, t; if (! polygon_is_rectangle (polygon)) { crooked = true; continue; } w = polygon->Points[2].X - polygon->Points[0].X; h = polygon->Points[1].Y - polygon->Points[0].Y; t = (w < h) ? w : h; x1 = polygon->Points[0].X + t/2; y1 = polygon->Points[0].Y + t/2; x2 = x1 + (w-t); y2 = y1 + (h-t); sprintf (num, "%d", pin_n++); CreateNewPad (Element, x1, y1, x2, y2, t, 2 * Settings.Keepaway, t + Settings.Keepaway, NULL, num, MakeFlags (SQUAREFLAG | onsolderflag)); MAYBE_WARN(); hasParts = true; } END_LOOP; } END_LOOP; } /* now add the silkscreen. NOTE: elements must have pads or pins too */ LINE_LOOP (&Buffer->Data->SILKLAYER); { if (line->Number && !NAMEONPCB_NAME (Element)) NAMEONPCB_NAME (Element) = strdup (line->Number); CreateNewLineInElement (Element, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, line->Thickness); hasParts = true; } END_LOOP; ARC_LOOP (&Buffer->Data->SILKLAYER); { CreateNewArcInElement (Element, arc->X, arc->Y, arc->Width, arc->Height, arc->StartAngle, arc->Delta, arc->Thickness); hasParts = true; } END_LOOP; if (!hasParts) { DestroyObject (PCB->Data, ELEMENT_TYPE, Element, Element, Element); Message (_("There was nothing to convert!\n" "Elements must have some silk, pads or pins.\n")); return (false); } if (crooked) Message (_("There were polygons that can't be made into pins!\n" "So they were not included in the element\n")); Element->MarkX = Buffer->X; Element->MarkY = Buffer->Y; if (SWAP_IDENT) SET_FLAG (ONSOLDERFLAG, Element); SetElementBoundingBox (PCB->Data, Element, &PCB->Font); ClearBuffer (Buffer); MoveObjectToBuffer (Buffer->Data, PCB->Data, ELEMENT_TYPE, Element, Element, Element); SetBufferBoundingBox (Buffer); return (true); } /*! * \brief Load PCB into buffer. * * Parse the file with enabled 'PCB mode' (see parser). * If successful, update some other stuff. */ bool LoadLayoutToBuffer (BufferType *Buffer, char *Filename) { PCBType *newPCB = CreateNewPCB (); /* new data isn't added to the undo list */ if (!ParsePCB (newPCB, Filename)) { /* clear data area and replace pointer */ ClearBuffer (Buffer); free (Buffer->Data); Buffer->Data = newPCB->Data; newPCB->Data = NULL; Buffer->X = newPCB->CursorX; Buffer->Y = newPCB->CursorY; RemovePCB (newPCB); Buffer->Data->pcb = PCB; return (true); } /* release unused memory */ RemovePCB (newPCB); Buffer->Data->pcb = PCB; return (false); } /*! * \brief Rotates the contents of the pastebuffer. */ void RotateBuffer (BufferType *Buffer, BYTE Number) { /* rotate vias */ VIA_LOOP (Buffer->Data); { r_delete_entry (Buffer->Data->via_tree, (BoxType *)via); ROTATE_VIA_LOWLEVEL (via, Buffer->X, Buffer->Y, Number); SetPinBoundingBox (via); r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0); } END_LOOP; /* elements */ ELEMENT_LOOP (Buffer->Data); { RotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y, Number); } END_LOOP; /* all layer related objects */ ALLLINE_LOOP (Buffer->Data); { r_delete_entry (layer->line_tree, (BoxType *)line); RotateLineLowLevel (line, Buffer->X, Buffer->Y, Number); r_insert_entry (layer->line_tree, (BoxType *)line, 0); } ENDALL_LOOP; ALLARC_LOOP (Buffer->Data); { r_delete_entry (layer->arc_tree, (BoxType *)arc); RotateArcLowLevel (arc, Buffer->X, Buffer->Y, Number); r_insert_entry (layer->arc_tree, (BoxType *)arc, 0); } ENDALL_LOOP; ALLTEXT_LOOP (Buffer->Data); { r_delete_entry (layer->text_tree, (BoxType *)text); RotateTextLowLevel (text, Buffer->X, Buffer->Y, Number); r_insert_entry (layer->text_tree, (BoxType *)text, 0); } ENDALL_LOOP; ALLPOLYGON_LOOP (Buffer->Data); { r_delete_entry (layer->polygon_tree, (BoxType *)polygon); RotatePolygonLowLevel (polygon, Buffer->X, Buffer->Y, Number); r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0); } ENDALL_LOOP; /* finally the origin and the bounding box */ ROTATE (Buffer->X, Buffer->Y, Buffer->X, Buffer->Y, Number); RotateBoxLowLevel (&Buffer->BoundingBox, Buffer->X, Buffer->Y, Number); crosshair_update_range(); } static void free_rotate (Coord *x, Coord *y, Coord cx, Coord cy, double cosa, double sina) { double nx, ny; Coord px = *x - cx; Coord py = *y - cy; nx = px * cosa + py * sina; ny = py * cosa - px * sina; *x = nx + cx; *y = ny + cy; } void FreeRotateElementLowLevel (DataType *Data, ElementType *Element, Coord X, Coord Y, double cosa, double sina, Angle angle) { /* solder side objects need a different orientation */ /* the text subroutine decides by itself if the direction * is to be corrected */ #if 0 ELEMENTTEXT_LOOP (Element); { if (Data && Data->name_tree[n]) r_delete_entry (Data->name_tree[n], (BoxType *)text); RotateTextLowLevel (text, X, Y, Number); } END_LOOP; #endif ELEMENTLINE_LOOP (Element); { free_rotate (&line->Point1.X, &line->Point1.Y, X, Y, cosa, sina); free_rotate (&line->Point2.X, &line->Point2.Y, X, Y, cosa, sina); SetLineBoundingBox (line); } END_LOOP; PIN_LOOP (Element); { /* pre-delete the pins from the pin-tree before their coordinates change */ if (Data) r_delete_entry (Data->pin_tree, (BoxType *)pin); RestoreToPolygon (Data, PIN_TYPE, Element, pin); free_rotate (&pin->X, &pin->Y, X, Y, cosa, sina); SetPinBoundingBox (pin); } END_LOOP; PAD_LOOP (Element); { /* pre-delete the pads before their coordinates change */ if (Data) r_delete_entry (Data->pad_tree, (BoxType *)pad); RestoreToPolygon (Data, PAD_TYPE, Element, pad); free_rotate (&pad->Point1.X, &pad->Point1.Y, X, Y, cosa, sina); free_rotate (&pad->Point2.X, &pad->Point2.Y, X, Y, cosa, sina); SetLineBoundingBox ((LineType *) pad); } END_LOOP; ARC_LOOP (Element); { free_rotate (&arc->X, &arc->Y, X, Y, cosa, sina); arc->StartAngle = NormalizeAngle (arc->StartAngle + angle); } END_LOOP; free_rotate (&Element->MarkX, &Element->MarkY, X, Y, cosa, sina); SetElementBoundingBox (Data, Element, &PCB->Font); ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element); } void FreeRotateBuffer (BufferType *Buffer, Angle angle) { double cosa, sina; cosa = cos(angle * M_PI/180.0); sina = sin(angle * M_PI/180.0); /* rotate vias */ VIA_LOOP (Buffer->Data); { r_delete_entry (Buffer->Data->via_tree, (BoxType *)via); free_rotate (&via->X, &via->Y, Buffer->X, Buffer->Y, cosa, sina); SetPinBoundingBox (via); r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0); } END_LOOP; /* elements */ ELEMENT_LOOP (Buffer->Data); { FreeRotateElementLowLevel (Buffer->Data, element, Buffer->X, Buffer->Y, cosa, sina, angle); } END_LOOP; /* all layer related objects */ ALLLINE_LOOP (Buffer->Data); { r_delete_entry (layer->line_tree, (BoxType *)line); free_rotate (&line->Point1.X, &line->Point1.Y, Buffer->X, Buffer->Y, cosa, sina); free_rotate (&line->Point2.X, &line->Point2.Y, Buffer->X, Buffer->Y, cosa, sina); SetLineBoundingBox (line); r_insert_entry (layer->line_tree, (BoxType *)line, 0); } ENDALL_LOOP; ALLARC_LOOP (Buffer->Data); { r_delete_entry (layer->arc_tree, (BoxType *)arc); free_rotate (&arc->X, &arc->Y, Buffer->X, Buffer->Y, cosa, sina); arc->StartAngle = NormalizeAngle (arc->StartAngle + angle); r_insert_entry (layer->arc_tree, (BoxType *)arc, 0); } ENDALL_LOOP; /* FIXME: rotate text */ ALLPOLYGON_LOOP (Buffer->Data); { r_delete_entry (layer->polygon_tree, (BoxType *)polygon); POLYGONPOINT_LOOP (polygon); { free_rotate (&point->X, &point->Y, Buffer->X, Buffer->Y, cosa, sina); } END_LOOP; SetPolygonBoundingBox (polygon); r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0); } ENDALL_LOOP; SetBufferBoundingBox (Buffer); crosshair_update_range(); } /* -------------------------------------------------------------------------- */ static const char freerotatebuffer_syntax[] = N_("FreeRotateBuffer([Angle])"); static const char freerotatebuffer_help[] = N_("Rotates the current paste buffer contents by the specified angle. The\n" "angle is given in degrees. If no angle is given, the user is prompted\n" "for one.\n"); /* %start-doc actions FreeRotateBuffer Rotates the contents of the pastebuffer by an arbitrary angle. If no angle is given, the user is prompted for one. %end-doc */ int ActionFreeRotateBuffer(int argc, char **argv, Coord x, Coord y) { char *angle_s; if (argc < 1) angle_s = gui->prompt_for (_("Enter Rotation (degrees, CCW):"), "0"); else angle_s = argv[0]; notify_crosshair_change (false); FreeRotateBuffer(PASTEBUFFER, strtod(angle_s, 0)); notify_crosshair_change (true); return 0; } /*! * \brief Initializes the buffers by allocating memory. */ void InitBuffers (void) { int i; for (i = 0; i < MAX_BUFFER; i++) Buffers[i].Data = CreateNewBuffer (); } void UninitBuffers (void) { int i; for (i = 0; i < MAX_BUFFER; i++) { ClearBuffer (Buffers+i); free (Buffers[i].Data); } } void SwapBuffers (void) { int i; for (i = 0; i < MAX_BUFFER; i++) SwapBuffer (&Buffers[i]); crosshair_update_range(); } void MirrorBuffer (BufferType *Buffer) { int i; if (Buffer->Data->ElementN) { Message (_("You can't mirror a buffer that has elements!\n")); return; } for (i = 0; i < max_copper_layer + SILK_LAYER; i++) { LayerType *layer = Buffer->Data->Layer + i; if (layer->TextN) { Message (_("You can't mirror a buffer that has text!\n")); return; } } /* set buffer offset to 'mark' position */ Buffer->X = SWAP_X (Buffer->X); Buffer->Y = SWAP_Y (Buffer->Y); VIA_LOOP (Buffer->Data); { via->X = SWAP_X (via->X); via->Y = SWAP_Y (via->Y); } END_LOOP; ALLLINE_LOOP (Buffer->Data); { line->Point1.X = SWAP_X (line->Point1.X); line->Point1.Y = SWAP_Y (line->Point1.Y); line->Point2.X = SWAP_X (line->Point2.X); line->Point2.Y = SWAP_Y (line->Point2.Y); } ENDALL_LOOP; ALLARC_LOOP (Buffer->Data); { r_delete_entry(layer->arc_tree, (BoxType*)arc); arc->X = SWAP_X (arc->X); arc->Y = SWAP_Y (arc->Y); arc->StartAngle = SWAP_ANGLE (arc->StartAngle); arc->Delta = SWAP_DELTA (arc->Delta); SetArcBoundingBox (arc); r_insert_entry(layer->arc_tree, (BoxType*)arc, 0); } ENDALL_LOOP; ALLPOLYGON_LOOP (Buffer->Data); { r_delete_entry(layer->polygon_tree, (BoxType*)polygon); POLYGONPOINT_LOOP (polygon); { point->X = SWAP_X (point->X); point->Y = SWAP_Y (point->Y); } END_LOOP; SetPolygonBoundingBox (polygon); r_insert_entry(layer->polygon_tree, (BoxType*)polygon, 0); } ENDALL_LOOP; SetBufferBoundingBox (Buffer); crosshair_update_range(); } /*! * \brief Flip components/tracks from one side to the other. */ static void SwapBuffer (BufferType *Buffer) { int j, k; Cardinal top_group, bottom_group; LayerType swap; ELEMENT_LOOP (Buffer->Data); { r_delete_element (Buffer->Data, element); MirrorElementCoordinates (Buffer->Data, element, 0); } END_LOOP; /* set buffer offset to 'mark' position */ Buffer->X = SWAP_X (Buffer->X); Buffer->Y = SWAP_Y (Buffer->Y); VIA_LOOP (Buffer->Data); { r_delete_entry (Buffer->Data->via_tree, (BoxType *)via); via->X = SWAP_X (via->X); via->Y = SWAP_Y (via->Y); SetPinBoundingBox (via); r_insert_entry (Buffer->Data->via_tree, (BoxType *)via, 0); } END_LOOP; ALLLINE_LOOP (Buffer->Data); { r_delete_entry (layer->line_tree, (BoxType *)line); line->Point1.X = SWAP_X (line->Point1.X); line->Point1.Y = SWAP_Y (line->Point1.Y); line->Point2.X = SWAP_X (line->Point2.X); line->Point2.Y = SWAP_Y (line->Point2.Y); SetLineBoundingBox (line); r_insert_entry (layer->line_tree, (BoxType *)line, 0); } ENDALL_LOOP; ALLARC_LOOP (Buffer->Data); { r_delete_entry (layer->arc_tree, (BoxType *)arc); arc->X = SWAP_X (arc->X); arc->Y = SWAP_Y (arc->Y); arc->StartAngle = SWAP_ANGLE (arc->StartAngle); arc->Delta = SWAP_DELTA (arc->Delta); SetArcBoundingBox (arc); r_insert_entry (layer->arc_tree, (BoxType *)arc, 0); } ENDALL_LOOP; ALLPOLYGON_LOOP (Buffer->Data); { r_delete_entry (layer->polygon_tree, (BoxType *)polygon); POLYGONPOINT_LOOP (polygon); { point->X = SWAP_X (point->X); point->Y = SWAP_Y (point->Y); } END_LOOP; SetPolygonBoundingBox (polygon); r_insert_entry (layer->polygon_tree, (BoxType *)polygon, 0); /* hmmm, how to handle clip */ } ENDALL_LOOP; ALLTEXT_LOOP (Buffer->Data); { r_delete_entry (layer->text_tree, (BoxType *)text); text->X = SWAP_X (text->X); text->Y = SWAP_Y (text->Y); TOGGLE_FLAG (ONSOLDERFLAG, text); SetTextBoundingBox (&PCB->Font, text); r_insert_entry (layer->text_tree, (BoxType *)text, 0); } ENDALL_LOOP; /* swap silkscreen layers */ swap = Buffer->Data->Layer[bottom_silk_layer]; Buffer->Data->Layer[bottom_silk_layer] = Buffer->Data->Layer[top_silk_layer]; Buffer->Data->Layer[top_silk_layer] = swap; /* swap layer groups when balanced */ top_group = GetLayerGroupNumberBySide (TOP_SIDE); bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); if (PCB->LayerGroups.Number[top_group] == PCB->LayerGroups.Number[bottom_group]) { for (j = k = 0; j < PCB->LayerGroups.Number[bottom_group]; j++) { int t1, t2; Cardinal top_number = PCB->LayerGroups.Entries[top_group][k]; Cardinal bottom_number = PCB->LayerGroups.Entries[bottom_group][j]; if (bottom_number >= max_copper_layer) continue; swap = Buffer->Data->Layer[bottom_number]; while (top_number >= max_copper_layer) { k++; top_number = PCB->LayerGroups.Entries[top_group][k]; } Buffer->Data->Layer[bottom_number] = Buffer->Data->Layer[top_number]; Buffer->Data->Layer[top_number] = swap; k++; /* move the thermal flags with the layers */ ALLPIN_LOOP (Buffer->Data); { t1 = TEST_THERM (bottom_number, pin); t2 = TEST_THERM (top_number, pin); ASSIGN_THERM (bottom_number, t2, pin); ASSIGN_THERM (top_number, t1, pin); } ENDALL_LOOP; VIA_LOOP (Buffer->Data); { t1 = TEST_THERM (bottom_number, via); t2 = TEST_THERM (top_number, via); ASSIGN_THERM (bottom_number, t2, via); ASSIGN_THERM (top_number, t1, via); } END_LOOP; } } SetBufferBoundingBox (Buffer); crosshair_update_range(); } /*! * \brief Moves the passed object to the passed buffer and removes it * from its original place. */ void * MoveObjectToBuffer (DataType *Destination, DataType *Src, int Type, void *Ptr1, void *Ptr2, void *Ptr3) { /* setup local identifiers used by move operations */ Dest = Destination; Source = Src; return (ObjectOperation (&MoveBufferFunctions, Type, Ptr1, Ptr2, Ptr3)); } /*! * \brief Adds the passed object to the passed buffer. */ void * CopyObjectToBuffer (DataType *Destination, DataType *Src, int Type, void *Ptr1, void *Ptr2, void *Ptr3) { /* setup local identifiers used by Add operations */ Dest = Destination; Source = Src; return (ObjectOperation (&AddBufferFunctions, Type, Ptr1, Ptr2, Ptr3)); } /* ---------------------------------------------------------------------- */ HID_Action rotate_action_list[] = { {"FreeRotateBuffer", 0, ActionFreeRotateBuffer, freerotatebuffer_syntax, freerotatebuffer_help}, {"LoadFootprint", 0, LoadFootprint, loadfootprint_syntax, loadfootprint_help} }; REGISTER_ACTIONS (rotate_action_list) pcb-4.2.2/src/strflags.h0000664000076400007640000000317013434555140012010 00000000000000/*! * \file src/strflags.h * * \brief Prototypes for strflags. * * The purpose of this interface is to make the file format able to * handle more than 32 flags, and to hide the internal details of * flags from the file format. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2005 DJ Delorie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA * * dj@delorie.com */ #ifndef PCB_STRFLAGS_H #define PCB_STRFLAGS_H FlagType string_to_flags (const char *flagstring, int (*error) (const char *msg)); char *flags_to_string (FlagType flags, int object_type); FlagType string_to_pcbflags (const char *flagstring, int (*error) (const char *msg)); char *pcbflags_to_string (FlagType flags); void uninit_strflags_buf (void); void uninit_strflags_layerlist (void); #endif /* PCB_STRFLAGS_H */ pcb-4.2.2/src/icons/0000775000076400007640000000000013611113567011204 500000000000000pcb-4.2.2/src/icons/lcurs.dat0000664000076400007640000000043711660653115012752 00000000000000#define lcurs_width 16 #define lcurs_height 16 static unsigned char lcurs_bits[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0x38, 0x1c, 0x1c, 0x3c, 0x1c, 0x38, 0x1c, 0x30, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f}; pcb-4.2.2/src/icons/hcurs.dat0000664000076400007640000000051311660653115012741 00000000000000#define hcurs_width 16 #define hcurs_height 16 #define hcurs_x_hot 7 #define hcurs_y_hot 9 static unsigned char hcurs_bits[] = { 0x80, 0x00, 0xc8, 0x09, 0xdc, 0x1d, 0xdc, 0x1d, 0xdc, 0x1d, 0xfc, 0xcf, 0x38, 0xee, 0x1f, 0x78, 0x0f, 0x78, 0x07, 0x30, 0x07, 0x30, 0x0e, 0x38, 0x1e, 0x3c, 0x3c, 0x1e, 0xf8, 0x0f, 0xf0, 0x0f}; pcb-4.2.2/src/icons/Makefile.am0000664000076400007640000000006312575072760013166 00000000000000EXTRA_DIST= hand.dat hcurs.dat lcurs.dat lock.dat pcb-4.2.2/src/icons/hand.dat0000664000076400007640000000073711660653115012537 00000000000000#define hand_width 21 #define hand_height 21 static unsigned char hand_bits[] = { 0x00, 0x02, 0x00, 0x20, 0x25, 0x00, 0x50, 0x55, 0x02, 0x50, 0x55, 0x05, 0x50, 0x55, 0x05, 0xd3, 0xd4, 0x06, 0x95, 0x48, 0x02, 0x19, 0x40, 0x01, 0x12, 0x00, 0x01, 0x04, 0x80, 0x00, 0x08, 0x80, 0x00, 0x10, 0x80, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x38, 0x26, 0x02, 0x48, 0x69, 0x02, 0x48, 0xe9, 0x02, 0x38, 0xaf, 0x02, 0x08, 0xa9, 0x03, 0x08, 0x29, 0x03, 0x08, 0x29, 0x02}; pcb-4.2.2/src/icons/lock.dat0000664000076400007640000000073711660653115012555 00000000000000#define lock_width 21 #define lock_height 21 static unsigned char lock_bits[] = { 0x00, 0x1f, 0x00, 0x80, 0x31, 0x00, 0x80, 0x20, 0x00, 0xc0, 0x60, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0xf0, 0xff, 0x01, 0x10, 0x00, 0x01, 0xf0, 0xff, 0x01, 0x10, 0x00, 0x01, 0xf0, 0xff, 0x01, 0x10, 0x00, 0x01, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x84, 0xb1, 0x04, 0x44, 0x8a, 0x04, 0x44, 0x8a, 0x02, 0x44, 0x8a, 0x01, 0x44, 0x8a, 0x02, 0x44, 0x8a, 0x04, 0x9c, 0xb1, 0x04}; pcb-4.2.2/src/icons/Makefile.in0000664000076400007640000003244613611062505013175 00000000000000# Makefile.in generated by automake 1.11.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = src/icons DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_gl.m4 \ $(top_srcdir)/m4/ax_check_glu.m4 \ $(top_srcdir)/m4/ax_lang_compiler_ms.m4 \ $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/codeset.m4 \ $(top_srcdir)/m4/extern-inline.m4 $(top_srcdir)/m4/fcntl-o.m4 \ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/glibc2.m4 \ $(top_srcdir)/m4/glibc21.m4 $(top_srcdir)/m4/iconv.m4 \ $(top_srcdir)/m4/intdiv0.m4 $(top_srcdir)/m4/intl.m4 \ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/intmax.m4 \ $(top_srcdir)/m4/inttypes-pri.m4 \ $(top_srcdir)/m4/inttypes_h.m4 $(top_srcdir)/m4/lcmessage.m4 \ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/lock.m4 \ $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/nls.m4 \ $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/printf-posix.m4 \ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/size_max.m4 \ $(top_srcdir)/m4/stdint_h.m4 $(top_srcdir)/m4/threadlib.m4 \ $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/visibility.m4 \ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wint_t.m4 \ $(top_srcdir)/m4/xsize.m4 $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/m4/m4_ax_func_mkdir.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = SOURCES = DIST_SOURCES = DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ ALL_LINGUAS = @ALL_LINGUAS@ AMTAR = @AMTAR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BTNMOD = @BTNMOD@ BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@ CAIRO_CFLAGS = @CAIRO_CFLAGS@ CAIRO_LIBS = @CAIRO_LIBS@ CATOBJEXT = @CATOBJEXT@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CC_OR_CXX = @CC_OR_CXX@ CFLAGS = @CFLAGS@ CFLAG_VISIBILITY = @CFLAG_VISIBILITY@ CONVERT = @CONVERT@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DATADIRNAME = @DATADIRNAME@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_LIBS = @DBUS_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DOC = @DOC@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FONTFILENAME = @FONTFILENAME@ GDLIB_CFLAGS = @GDLIB_CFLAGS@ GDLIB_CONFIG = @GDLIB_CONFIG@ GDLIB_LIBS = @GDLIB_LIBS@ GENCAT = @GENCAT@ GERBV = @GERBV@ GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ GLIBC2 = @GLIBC2@ GLIBC21 = @GLIBC21@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GLU_CFLAGS = @GLU_CFLAGS@ GLU_LIBS = @GLU_LIBS@ GL_CFLAGS = @GL_CFLAGS@ GL_LIBS = @GL_LIBS@ GMSGFMT = @GMSGFMT@ GMSGFMT_015 = @GMSGFMT_015@ GNUM4 = @GNUM4@ GREP = @GREP@ GSCHEM = @GSCHEM@ GTKGLEXT_CFLAGS = @GTKGLEXT_CFLAGS@ GTKGLEXT_LIBS = @GTKGLEXT_LIBS@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_LIBS = @GTK_LIBS@ GTK_UPDATE_ICON_CACHE_BIN = @GTK_UPDATE_ICON_CACHE_BIN@ HAVE_ASPRINTF = @HAVE_ASPRINTF@ HAVE_NEWLOCALE = @HAVE_NEWLOCALE@ HAVE_POSIX_PRINTF = @HAVE_POSIX_PRINTF@ HAVE_SNPRINTF = @HAVE_SNPRINTF@ HAVE_VISIBILITY = @HAVE_VISIBILITY@ HAVE_WPRINTF = @HAVE_WPRINTF@ HIDLIBS = @HIDLIBS@ HIDLIST = @HIDLIST@ IM_ANIMATE = @IM_ANIMATE@ IM_COMPARE = @IM_COMPARE@ IM_COMPOSITE = @IM_COMPOSITE@ IM_CONVERT = @IM_CONVERT@ IM_DISPLAY = @IM_DISPLAY@ IM_MONTAGE = @IM_MONTAGE@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTOBJEXT = @INSTOBJEXT@ INTLBISON = @INTLBISON@ INTLLIBS = @INTLLIBS@ INTLOBJS = @INTLOBJS@ INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ INTLTOOL_MERGE = @INTLTOOL_MERGE@ INTLTOOL_PERL = @INTLTOOL_PERL@ INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ INTL_DEFAULT_VERBOSITY = @INTL_DEFAULT_VERBOSITY@ INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ KDEDATADIR = @KDEDATADIR@ KPSEWHICH = @KPSEWHICH@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LEX_PATH = @LEX_PATH@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBMULTITHREAD = @LIBMULTITHREAD@ LIBOBJS = @LIBOBJS@ LIBPTH = @LIBPTH@ LIBPTH_PREFIX = @LIBPTH_PREFIX@ LIBRARYFILENAME = @LIBRARYFILENAME@ LIBS = @LIBS@ LIBTHREAD = @LIBTHREAD@ LTLIBC = @LTLIBC@ LTLIBICONV = @LTLIBICONV@ LTLIBINTL = @LTLIBINTL@ LTLIBMULTITHREAD = @LTLIBMULTITHREAD@ LTLIBOBJS = @LTLIBOBJS@ LTLIBPTH = @LTLIBPTH@ LTLIBTHREAD = @LTLIBTHREAD@ M4 = @M4@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MKINFO = @MKINFO@ MSGFMT = @MSGFMT@ MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PCB = @PCB@ PCBLIBDIR = @PCBLIBDIR@ PCBTREEDIR = @PCBTREEDIR@ PCBTREEPATH = @PCBTREEPATH@ PDFLATEX = @PDFLATEX@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ POSUB = @POSUB@ PPMTOWINICON = @PPMTOWINICON@ PRI_MACROS_BROKEN = @PRI_MACROS_BROKEN@ PS2PDF = @PS2PDF@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ SETENV = @SETENV@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TEXI2DVI = @TEXI2DVI@ TOPDIRS = @TOPDIRS@ UPDATE_DESKTOP_DATABASE = @UPDATE_DESKTOP_DATABASE@ UPDATE_MIME_DATABASE = @UPDATE_MIME_DATABASE@ USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@ USE_NLS = @USE_NLS@ VERSION = @VERSION@ WIN32 = @WIN32@ WINDRES = @WINDRES@ WISH = @WISH@ WITHGUI = @WITHGUI@ WOE32 = @WOE32@ WOE32DLL = @WOE32DLL@ XDGDATADIR = @XDGDATADIR@ XGETTEXT = @XGETTEXT@ XGETTEXT_015 = @XGETTEXT_015@ XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ XHOST = @XHOST@ XMKMF = @XMKMF@ XPMTOPPM = @XPMTOPPM@ X_CFLAGS = @X_CFLAGS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ X_LIBS = @X_LIBS@ X_PRE_LIBS = @X_PRE_LIBS@ YACC = @YACC@ YACC_PATH = @YACC_PATH@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ ax_pthread_config = @ax_pthread_config@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = hand.dat hcurs.dat lcurs.dat lock.dat all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/icons/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign src/icons/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): tags: TAGS TAGS: ctags: CTAGS CTAGS: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ `test -z '$(STRIP)' || \ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic distclean \ distclean-generic distdir dvi dvi-am html html-am info info-am \ install install-am install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: pcb-4.2.2/src/drill.h0000664000076400007640000000233713434555140011275 00000000000000/*! * \file src/drill.h * * \brief . * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This module, drill.h, was written and is Copyright (C) 1997 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ DrillInfoType * GetDrillInfo (DataType *); void FreeDrillInfo (DrillInfoType *); void RoundDrillInfo (DrillInfoType *, int); pcb-4.2.2/src/clip.c0000664000076400007640000000626313434555140011113 00000000000000/*! * \file src/clip.c * * \brief Functions for inserting points into objects. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 2004 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "global.h" #include "data.h" #include "draw.h" #include "mymem.h" #ifdef HAVE_LIBDMALLOC #include #endif /*! * \brief Clip the line to the clipBox. * * Clip X,Y to the given bounding box, plus a margin. * * \return true if something to be drawn, false if the whole thing is * clipped. */ bool ClipLine (double minx, double miny, double maxx, double maxy, double *x1, double *y1, double *x2, double *y2, double margin) { double d, r; minx -= margin; miny -= margin; maxx += margin; maxy += margin; /* clip first point on left side */ if (*x1 < minx) { if (*x2 < minx) return false; d = *x2 - *x1; r = (minx - *x1) / d; *x1 = minx; *y1 += r * (*y2 - *y1); } /* clip second point on left side */ if (*x2 < minx) { d = *x1 - *x2; r = (minx - *x2) / d; *x2 = minx; *y2 += r * (*y1 - *y2); } /* clip first point on right side */ if (*x1 > maxx) { if (*x2 > maxx) return false; d = *x2 - *x1; r = (maxx - *x1) / d; *x1 = maxx; *y1 += r * (*y2 - *y1); } /* clip second point on right side */ if (*x2 > maxx) { d = *x1 - *x2; r = (maxx - *x2) / d; *x2 = maxx; *y2 += r * (*y1 - *y2); } /* clip first point on top */ if (*y1 < miny) { if (*y2 < miny) return false; d = *y2 - *y1; r = (miny - *y1) / d; *y1 = miny; *x1 += r * (*x2 - *x1); } /* clip second point on top */ if (*y2 < miny) { d = *y1 - *y2; r = (miny - *y2) / d; *y2 = miny; *x2 += r * (*x1 - *x2); } /* clip first point on bottom */ if (*y1 > maxy) { if (*y2 > maxy) return false; d = *y2 - *y1; r = (maxy - *y1) / d; *y1 = maxy; *x1 += r * (*x2 - *x1); } /* clip second point on top */ if (*y2 > maxy) { d = *y1 - *y2; r = (maxy - *y2) / d; *y2 = maxy; *x2 += r * (*x1 - *x2); } return true; } pcb-4.2.2/src/polyarea.h0000664000076400007640000001215113533277055012004 00000000000000/*! * \file src/polyarea.h * * \brief poly_Boolean: a polygon clip library. * *
* *

Copyright.

\n * * Copyright (C) 1997 Alexey Nikitin, Michael Leonov * * leonov@propro.iis.nsk.su * * Copyright (C) 1997 Klamer Schutte (minor patches) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, 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 * Library General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PCB_POLYAREA_H #define PCB_POLYAREA_H #ifdef __cplusplus extern "C" { #endif typedef int BOOLp; #ifndef FALSE enum { FALSE = 0, TRUE = 1 }; #endif /* What do these stand for? */ #define PLF_DIR 1 #define PLF_INV 0 #define PLF_MARK 1 #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) #endif #ifndef max #define max(x, y) ((x) > (y) ? (x) : (y)) #endif typedef Coord vertex[2]; /*!< longing point representation of coordinates. */ typedef vertex Vector; #define VertexEqu(a,b) (memcmp((a),(b),sizeof(Vector))==0) #define VertexCpy(a,b) memcpy((a),(b),sizeof(Vector)) extern Vector vect_zero; enum { err_no_memory = 2, err_bad_parm = 3, err_ok = 0 }; /* Cross Vertex Connectivity List */ typedef struct CVCList CVCList; typedef struct VNODE VNODE; struct CVCList { double angle; VNODE *parent; CVCList *prev, *next, *head; char poly, side; }; /* A node of a PLINE. * * A segment is defined by the current node and the next node. * */ struct VNODE { VNODE *next, *prev, *shared; struct { unsigned int status:3; unsigned int mark:1; } Flags; CVCList *cvc_prev; CVCList *cvc_next; Vector point; }; /* This structure defines a contour. The segments are comprise the * various VNODEs, which are organized in an ordered list. * * PLINEs have an orientation, positive or negative, depending on if the * VNODES of the contour are organized in a generally clockwise or counter * clockwise order. Positive contours define the perimeters of polygons, * negative contours define holes in contours. * */ typedef struct PLINE PLINE; struct PLINE { /* segment bounding box */ Coord xmin, ymin, xmax, ymax; PLINE *next; VNODE head; unsigned int Count; double area; rtree_t *tree; bool is_round; Coord cx, cy; Coord radius; struct { unsigned int status:3; unsigned int orient:1; } Flags; }; PLINE *poly_NewContour(Vector v); void poly_IniContour(PLINE * c); void poly_ClrContour(PLINE * c); /* clears list of vertices */ void poly_DelContour(PLINE ** c); BOOLp poly_CopyContour(PLINE ** dst, PLINE * src); void poly_PreContour(PLINE * c, BOOLp optimize); /* prepare contour */ void poly_InvContour(PLINE * c); /* invert contour */ VNODE *poly_CreateNode(Vector v); void poly_InclVertex(VNODE * after, VNODE * node); void poly_ExclVertex(VNODE * node); typedef struct POLYAREA POLYAREA; struct POLYAREA { /* this type is a double linked list, forward, backwards */ POLYAREA *f, *b; /* linked list of contours defining the perimeter and holes. */ PLINE *contours; /* rtree of segment bounding boxes, for faster searching */ rtree_t *contour_tree; }; BOOLp poly_M_Copy0(POLYAREA ** dst, const POLYAREA * srcfst); void poly_M_Incl(POLYAREA **list, POLYAREA *a); BOOLp poly_Copy0(POLYAREA **dst, const POLYAREA *src); BOOLp poly_Copy1(POLYAREA *dst, const POLYAREA *src); BOOLp poly_InclContour(POLYAREA * p, PLINE * c); BOOLp poly_ExclContour(POLYAREA * p, PLINE * c); BOOLp poly_ChkContour(PLINE * a); BOOLp poly_CheckInside(POLYAREA * c, Vector v0); BOOLp Touching(POLYAREA *p1, POLYAREA *p2); /* tools for clipping */ /*! * \brief Checks whether point lies within contour independently of its * orientation. */ int poly_InsideContour(PLINE *c, Vector v); int poly_ContourInContour(PLINE * poly, PLINE * inner); POLYAREA *poly_Create(void); void poly_Free(POLYAREA **p); void poly_Init(POLYAREA *p); void poly_FreeContours(PLINE **pl); BOOLp poly_Valid(POLYAREA *p); enum PolygonBooleanOperation { PBO_UNITE, PBO_ISECT, PBO_SUB, PBO_XOR }; double vect_dist2 (Vector v1, Vector v2); double vect_det2 (Vector v1, Vector v2); double vect_len2 (Vector v1); int vect_inters2 (Vector A, Vector B, Vector C, Vector D, Vector S1, Vector S2); int poly_Boolean(const POLYAREA * a, const POLYAREA * b, POLYAREA ** res, int action); int poly_Boolean_free(POLYAREA * a, POLYAREA * b, POLYAREA ** res, int action); int poly_AndSubtract_free(POLYAREA * a, POLYAREA * b, POLYAREA ** aandb, POLYAREA ** aminusb); int SavePOLYAREA( POLYAREA *PA, char * fname); #ifdef __cplusplus } #endif #endif /* PCB_POLYAREA_H */ pcb-4.2.2/src/strflags.c0000664000076400007640000003564013434555140012012 00000000000000/*! * \file src/strflags.c * * \brief strflags. * * The purpose of this interface is to make the file format able to * handle more than 32 flags, and to hide the internal details of * flags from the file format. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2005 DJ Delorie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA * * dj@delorie.com */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "globalconst.h" #include "global.h" #include "compat.h" #include "hid.h" #include "strflags.h" #ifdef HAVE_LIBDMALLOC #include #endif /* Because all the macros expect it, that's why. */ typedef struct { FlagType Flags; } FlagHolder; /*! * Be careful to list more specific flags first, followed by general * flags, when two flags use the same bit. For example, "onsolder" is * for elements only, while "auto" is for everything else. They use * the same bit, but onsolder is listed first so that elements will * use it and not auto. * * Thermals are handled separately, as they're layer-selective. */ typedef struct { int mask; /*!< This is the bit that we're setting. */ char *name; /*!< The name used in the output file. */ int nlen; #define N(x) x, sizeof(x)-1 int object_types; /*!< If set, this entry won't be output unless the * object type is one of these. */ } FlagBitsType; static FlagBitsType object_flagbits[] = { { PINFLAG, N ("pin"), ALL_TYPES }, { VIAFLAG, N ("via"), ALL_TYPES }, { FOUNDFLAG, N ("found"), ALL_TYPES }, { HOLEFLAG, N ("hole"), PIN_TYPES }, { RATFLAG, N ("rat"), RATLINE_TYPE }, { PININPOLYFLAG, N ("pininpoly"), PIN_TYPES | PAD_TYPE }, { CLEARPOLYFLAG, N ("clearpoly"), POLYGON_TYPE }, { HIDENAMEFLAG, N ("hidename"), ELEMENT_TYPE }, { DISPLAYNAMEFLAG, N ("showname"), ELEMENT_TYPE }, { CLEARLINEFLAG, N ("clearline"), LINE_TYPE | ARC_TYPE | TEXT_TYPE }, { SELECTEDFLAG, N ("selected"), ALL_TYPES }, { ONSOLDERFLAG, N ("onsolder"), ELEMENT_TYPE | PAD_TYPE | TEXT_TYPE | ELEMENTNAME_TYPE }, { AUTOFLAG, N ("auto"), ALL_TYPES }, { SQUAREFLAG, N ("square"), PIN_TYPES | PAD_TYPE }, { RUBBERENDFLAG, N ("rubberend"), LINE_TYPE | ARC_TYPE }, { WARNFLAG, N ("warn"), PIN_TYPES | PAD_TYPE }, { USETHERMALFLAG, N ("usetherm"), PIN_TYPES | LINE_TYPE | ARC_TYPE }, { OCTAGONFLAG, N ("octagon"), PIN_TYPES | PAD_TYPE }, { DRCFLAG, N ("drc"), ALL_TYPES }, { LOCKFLAG, N ("lock"), ALL_TYPES }, { EDGE2FLAG, N ("edge2"), ALL_TYPES }, { FULLPOLYFLAG, N ("fullpoly"), POLYGON_TYPE}, { NOPASTEFLAG, N ("nopaste"), PAD_TYPE }, { CONNECTEDFLAG, N ("connected"), ALL_TYPES } }; static FlagBitsType pcb_flagbits[] = { { SHOWNUMBERFLAG, N ("shownumber"), ALL_TYPES }, { LOCALREFFLAG, N ("localref"), ALL_TYPES }, { CHECKPLANESFLAG, N ("checkplanes"), ALL_TYPES }, { SHOWDRCFLAG, N ("showdrc"), ALL_TYPES }, { RUBBERBANDFLAG, N ("rubberband"), ALL_TYPES }, { DESCRIPTIONFLAG, N ("description"), ALL_TYPES }, { NAMEONPCBFLAG, N ("nameonpcb"), ALL_TYPES }, { AUTODRCFLAG, N ("autodrc"), ALL_TYPES }, { ALLDIRECTIONFLAG, N ("alldirection"), ALL_TYPES }, { SWAPSTARTDIRFLAG, N ("swapstartdir"), ALL_TYPES }, { UNIQUENAMEFLAG, N ("uniquename"), ALL_TYPES }, { CLEARNEWFLAG, N ("clearnew"), ALL_TYPES }, { NEWFULLPOLYFLAG, N ("newfullpoly"), ALL_TYPES }, { SNAPPINFLAG, N ("snappin"), ALL_TYPES }, { SHOWMASKFLAG, N ("showmask"), ALL_TYPES }, { THINDRAWFLAG, N ("thindraw"), ALL_TYPES }, { ORTHOMOVEFLAG, N ("orthomove"), ALL_TYPES }, { LIVEROUTEFLAG, N ("liveroute"), ALL_TYPES }, { THINDRAWPOLYFLAG, N ("thindrawpoly"), ALL_TYPES }, { LOCKNAMESFLAG, N ("locknames"), ALL_TYPES }, { ONLYNAMESFLAG, N ("onlynames"), ALL_TYPES }, { HIDENAMESFLAG, N ("hidenames"), ALL_TYPES }, { AUTOBURIEDVIASFLAG, N ("autoburiedvias"), ALL_TYPES }, }; #undef N /* * This helper function maintains a small list of buffers which are * used by flags_to_string(). Each buffer is allocated from the heap, * but the caller must not free them (they get realloced when they're * reused, but never completely freed). */ static struct { char *ptr; int len; } buffers[10]; static int bufptr = 0; static char * alloc_buf (int len) { #define B buffers[bufptr] len++; bufptr = (bufptr + 1) % 10; if (B.len < len) { if (B.ptr) B.ptr = (char *) realloc (B.ptr, len); else B.ptr = (char *) malloc (len); B.len = len; } return B.ptr; #undef B } void uninit_strflags_buf (void) { int n; for (n = 0; n < 10; n++) { if (buffers[n].ptr != NULL) { free (buffers[n].ptr); buffers[n].ptr = NULL; } } } static char *layers = 0; static int max_layers = 0, num_layers = 0; /*! * \brief Grow layer list. * * This routine manages a list of layer-specific flags. * * Callers should call grow_layer_list(0) to reset the list, and * set_layer_list(layer,1) to set bits in the layer list. * * The results are stored in layers[], which has \c num_layers valid * entries. */ static void grow_layer_list (int num) { if (layers == 0) { layers = (char *) calloc (num > 0 ? num : 1, 1); max_layers = num; } else if (num > max_layers) { max_layers = num; layers = (char *) realloc (layers, max_layers); } if (num > num_layers) memset (layers + num_layers, 0, num - num_layers - 1); num_layers = num; return; } void uninit_strflags_layerlist (void) { if (layers != NULL) { free (layers); layers = NULL; num_layers = max_layers = 0; } } /*! * \brief Set layer list. * * This routine manages a list of layer-specific flags. * * Callers should call grow_layer_list(0) to reset the list, and * set_layer_list(layer,1) to set bits in the layer list. * * The results are stored in layers[], which has \c num_layers valid * entries. */ static inline void set_layer_list (int layer, int v) { if (layer >= num_layers) grow_layer_list (layer + 1); layers[layer] = v; } /*! * \brief Parse layer list. * * parse_layer_list() is passed a pointer to a string, and parses a * list of integer which reflect layers to be flagged. * * It returns a pointer to the first character following the list. * * The syntax of the list is a paren-surrounded, comma-separated list of * integers and/or pairs of integers separated by a dash * (like "(1,2,3-7)"). * * Spaces and other punctuation are not allowed. * * The results are stored in \c layers[]. * * \return a pointer to the first character past the list. */ static const char * parse_layer_list (const char *bp, int (*error) (const char *)) { const char *orig_bp = bp; int l = 0, range = -1; int value = 1; grow_layer_list (0); while (*bp) { if (*bp == '+') value = 2; else if (*bp == 'S') value = 3; else if (*bp == 'X') value = 4; else if (*bp == 't') value = 5; else if (*bp == ')' || *bp == ',' || *bp == '-') { if (range == -1) range = l; while (range <= l) set_layer_list (range++, value); if (*bp == '-') range = l; else range = -1; value = 1; l = 0; } else if (isdigit ((int) *bp)) l = l * 10 + (*bp - '0'); else if (error) { char *fmt = "Syntax error parsing layer list \"%.*s\" at %c"; char *msg = alloc_buf (strlen (fmt) + strlen (orig_bp)); sprintf (msg, fmt, bp - orig_bp + 5, orig_bp, *bp); error (msg); error = NULL; } if (*bp == ')') return bp + 1; bp++; } return bp; } /*! * \brief Number of character the value "i" requires when printed. */ static int printed_int_length (int i, int j) { int rv; if (i < 10) return 1 + (j ? 1 : 0); if (i < 100) return 2 + (j ? 1 : 0); for (rv = 1; i >= 10; rv++) i /= 10; return rv + (j ? 1 : 0); } /*! * \brief Print layer list. * * print_layer_list() uses the flags set in layers[] to build a string * that represents them, using the syntax described below. * * The syntax of the list is a paren-surrounded, comma-separated list of * integers and/or pairs of integers separated by a dash * (like "(1,2,3-7)"). * * Spaces and other punctuation are not allowed. * * \return a pointer to an internal buffer which is overwritten with * each new call. */ static char * print_layer_list () { static char *buf = 0; static int buflen = 0; int len, i, j; char *bp; len = 2; for (i = 0; i < num_layers; i++) if (layers[i]) len += 1 + printed_int_length (i, layers[i]); if (buflen < len) { if (buf) buf = (char *) realloc (buf, len); else buf = (char *) malloc (len); buflen = len; } bp = buf; *bp++ = '('; for (i = 0; i < num_layers; i++) if (layers[i]) { /* 0 0 1 1 1 0 0 */ /* i j */ for (j = i + 1; j < num_layers && layers[j] == 1; j++) ; if (j > i + 2) { sprintf (bp, "%d-%d,", i, j - 1); i = j - 1; } else switch (layers[i]) { case 1: sprintf (bp, "%d,", i); break; case 2: sprintf (bp, "%d+,", i); break; case 3: sprintf (bp, "%dS,", i); break; case 4: sprintf (bp, "%dX,", i); break; case 5: default: sprintf (bp, "%dt,", i); break; } bp += strlen (bp); } bp[-1] = ')'; *bp = 0; return buf; } static int error_ignore (const char *msg) { /* do nothing */ return 0; } static FlagType empty_flags; static FlagType common_string_to_flags (const char *flagstring, int (*error) (const char *msg), FlagBitsType *flagbits, int n_flagbits) { const char *fp, *ep; int flen; FlagHolder rv; int i; rv.Flags = empty_flags; if (error == 0) error = error_ignore; if (flagstring == NULL) return empty_flags; fp = ep = flagstring; if (*fp == '"') ep = ++fp; while (*ep && *ep != '"') { int found = 0; for (ep = fp; *ep && *ep != ',' && *ep != '"' && *ep != '('; ep++) ; flen = ep - fp; if (*ep == '(') ep = parse_layer_list (ep + 1, error); if (flen == 7 && memcmp (fp, "thermal", 7) == 0) { for (i = 0; i < MAX_LAYER && i < num_layers; i++) if (layers[i]) ASSIGN_THERM (i, layers[i], &rv); } else { for (i = 0; i < n_flagbits; i++) if (flagbits[i].nlen == flen && memcmp (flagbits[i].name, fp, flen) == 0) { found = 1; SET_FLAG (flagbits[i].mask, &rv); break; } if (!found) { const char *fmt = "Unknown flag: \"%.*s\" ignored"; char *msg = alloc_buf (strlen (fmt) + flen); sprintf (msg, fmt, flen, fp); error (msg); } } fp = ep + 1; } return rv.Flags; } /*! * \brief Convert strings to flags. * * When passed a string, parse it and return an appropriate set of * flags. * * Errors cause error() to be called with a suitable message; * if error is NULL, errors are ignored. */ FlagType string_to_flags (const char *flagstring, int (*error) (const char *msg)) { return common_string_to_flags (flagstring, error, object_flagbits, ENTRIES (object_flagbits)); } /*! * \brief Convert strings to PCB flags. * * When passed a string, parse it and return an appropriate set of * flags. * * Errors cause error() to be called with a suitable message; * if error is NULL, errors are ignored. */ FlagType string_to_pcbflags (const char *flagstring, int (*error) (const char *msg)) { return common_string_to_flags (flagstring, error, pcb_flagbits, ENTRIES (pcb_flagbits)); } /*! * \brief Common flags converted to strings. * * Given a set of flags for a given type of object, return a string * which reflects those flags. * * The only requirement is that this string be parseable by string_to_flags. * * \note This function knows a little about what kinds of flags * will be automatically set by parsing, so it won't (for example) * include the "via" flag for VIA_TYPEs because it knows those get * forcibly set when vias are parsed. * * \warning Currently, there is no error handling :-P */ static char * common_flags_to_string (FlagType flags, int object_type, FlagBitsType *flagbits, int n_flagbits) { int len; int i; FlagHolder fh, savef; char *buf, *bp; fh.Flags = flags; switch (object_type) { case VIA_TYPE: CLEAR_FLAG (VIAFLAG, &fh); break; case RATLINE_TYPE: CLEAR_FLAG (RATFLAG, &fh); break; case PIN_TYPE: CLEAR_FLAG (PINFLAG, &fh); break; } savef = fh; len = 3; /* for "()\0" */ for (i = 0; i < n_flagbits; i++) if ((flagbits[i].object_types & object_type) && (TEST_FLAG (flagbits[i].mask, &fh))) { len += flagbits[i].nlen + 1; CLEAR_FLAG (flagbits[i].mask, &fh); } if (TEST_ANY_THERMS (&fh)) { len += sizeof ("thermal()"); for (i = 0; i < MAX_LAYER; i++) if (TEST_THERM (i, &fh)) len += printed_int_length (i, GET_THERM (i, &fh)) + 1; } bp = buf = alloc_buf (len + 2); *bp++ = '"'; fh = savef; for (i = 0; i < n_flagbits; i++) if (flagbits[i].object_types & object_type && (TEST_FLAG (flagbits[i].mask, &fh))) { if (bp != buf + 1) *bp++ = ','; strcpy (bp, flagbits[i].name); bp += flagbits[i].nlen; CLEAR_FLAG (flagbits[i].mask, &fh); } if (TEST_ANY_THERMS (&fh)) { if (bp != buf + 1) *bp++ = ','; strcpy (bp, "thermal"); bp += strlen ("thermal"); grow_layer_list (0); for (i = 0; i < MAX_LAYER; i++) if (TEST_THERM (i, &fh)) set_layer_list (i, GET_THERM (i, &fh)); strcpy (bp, print_layer_list ()); bp += strlen (bp); } *bp++ = '"'; *bp = 0; return buf; } /*! * \brief Object flags converted to strings. * * Given a set of flags for a given object type, return a string which * can be output to a file. * * The returned pointer must not be freed. */ char * flags_to_string (FlagType flags, int object_type) { return common_flags_to_string (flags, object_type, object_flagbits, ENTRIES (object_flagbits)); } /*! * \brief PCB flags converted to strings. */ char * pcbflags_to_string (FlagType flags) { return common_flags_to_string (flags, ALL_TYPES, pcb_flagbits, ENTRIES (pcb_flagbits)); } pcb-4.2.2/src/copy.h0000664000076400007640000000315513434555140011140 00000000000000/*! * \file src/copy.h * * \brief Prototypes for copy routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_COPY_H #define PCB_COPY_H #include "global.h" /* --------------------------------------------------------------------------- * some defines */ #define COPY_TYPES \ (VIA_TYPE | LINE_TYPE | TEXT_TYPE | \ ELEMENT_TYPE | ELEMENTNAME_TYPE | POLYGON_TYPE | ARC_TYPE) PolygonType * CopyPolygonLowLevel (PolygonType *, PolygonType *); ElementType * CopyElementLowLevel (DataType *, ElementType *, bool, Coord, Coord, int mask_flags); bool CopyPastebufferToLayout (Coord, Coord); void *CopyObject (int, void *, void *, void *, Coord, Coord); #endif pcb-4.2.2/src/create.c0000664000076400007640000006756513533277055011451 00000000000000/*! * \file src/create.c * * \brief Functions used to create vias, pins ... * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996, 2005 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "global.h" #include "create.h" #include "data.h" #include "draw.h" #include "error.h" #include "hid.h" /* REGISTER_ACTIONS */ #include "mymem.h" #include "misc.h" #include "parse_l.h" #include "pcb-printf.h" #include "polygon.h" #include "rtree.h" #include "search.h" #include "set.h" #include "undo.h" #include "vendor.h" #ifdef HAVE_LIBDMALLOC #include #endif /* --------------------------------------------------------------------------- * some local identifiers */ static long int ID = 1; /*!< Current object ID; incremented after each creation of an object */ static bool be_lenient = false; /* ---------------------------------------------------------------------- * some local prototypes */ static void AddTextToElement (TextType *, FontType *, Coord, Coord, unsigned, char *, int, FlagType); /*! * \brief Set the lenience mode. * * \c TRUE during file loads, for example to allow overlapping vias.\n * \c FALSE otherwise, to stop the user from doing normally dangerous * things. */ void CreateBeLenient (bool v) { be_lenient = v; } /*! * \brief Creates a new paste buffer. */ DataType * CreateNewBuffer (void) { DataType *data; data = (DataType *) calloc (1, sizeof (DataType)); data->pcb = (PCBType *) PCB; return data; } /*! * \brief Perhaps PCB should internally just use the Settings colors? * * For now, use this to set PCB colors so the config can reassign PCB * colors. */ void pcb_colors_from_settings (PCBType *ptr) { int i; /* copy default settings */ ptr->ConnectedColor = Settings.ConnectedColor; ptr->FoundColor = Settings.FoundColor; ptr->ElementColor = Settings.ElementColor; ptr->RatColor = Settings.RatColor; ptr->InvisibleObjectsColor = Settings.InvisibleObjectsColor; ptr->InvisibleMarkColor = Settings.InvisibleMarkColor; ptr->ElementSelectedColor = Settings.ElementSelectedColor; ptr->RatSelectedColor = Settings.RatSelectedColor; ptr->PinColor = Settings.PinColor; ptr->PinSelectedColor = Settings.PinSelectedColor; ptr->PinNameColor = Settings.PinNameColor; ptr->ViaColor = Settings.ViaColor; ptr->ViaSelectedColor = Settings.ViaSelectedColor; ptr->WarnColor = Settings.WarnColor; ptr->MaskColor = Settings.MaskColor; for (i = 0; i < MAX_LAYER; i++) { ptr->Data->Layer[i].Color = Settings.LayerColor[i]; ptr->Data->Layer[i].SelectedColor = Settings.LayerSelectedColor[i]; } ptr->Data->Layer[top_silk_layer].Color = Settings.ShowBottomSide ? Settings.InvisibleObjectsColor : Settings.ElementColor; ptr->Data->Layer[top_silk_layer].SelectedColor = Settings.ElementSelectedColor; ptr->Data->Layer[bottom_silk_layer].Color = Settings.ShowBottomSide ? Settings.ElementColor : Settings.InvisibleObjectsColor; ptr->Data->Layer[bottom_silk_layer].SelectedColor = Settings.ElementSelectedColor; } /*! * \brief Creates a new PCB. */ PCBType * CreateNewPCB (void) { PCBType *ptr; int i; /* allocate memory, switch all layers on and copy resources */ ptr = (PCBType *)calloc (1, sizeof (PCBType)); ptr->Data = CreateNewBuffer (); ptr->Data->pcb = (PCBType *) ptr; ptr->Data->polyClip = 1; ptr->ThermStyle = 4; ptr->IsleArea = 2.e8; ptr->SilkActive = false; ptr->RatDraw = false; SET_FLAG (NAMEONPCBFLAG, ptr); if (Settings.ShowNumber) SET_FLAG (SHOWNUMBERFLAG, ptr); if (Settings.AllDirectionLines) SET_FLAG (ALLDIRECTIONFLAG, ptr); ptr->Clipping = 1; /* this is the most useful starting point for now */ if (Settings.RubberBandMode) SET_FLAG (RUBBERBANDFLAG, ptr); if (Settings.SwapStartDirection) SET_FLAG (SWAPSTARTDIRFLAG, ptr); if (Settings.UniqueNames) SET_FLAG (UNIQUENAMEFLAG, ptr); if (Settings.SnapPin) SET_FLAG (SNAPPINFLAG, ptr); if (Settings.ClearLine) SET_FLAG (CLEARNEWFLAG, ptr); if (Settings.FullPoly) SET_FLAG (NEWFULLPOLYFLAG, ptr); if (Settings.OrthogonalMoves) SET_FLAG (ORTHOMOVEFLAG, ptr); if (Settings.liveRouting) SET_FLAG (LIVEROUTEFLAG, ptr); if (Settings.ShowDRC) SET_FLAG (SHOWDRCFLAG, ptr); if (Settings.AutoDRC) SET_FLAG (AUTODRCFLAG, ptr); if (Settings.AutoBuriedVias) SET_FLAG (AUTOBURIEDVIASFLAG, ptr); ptr->Grid = Settings.Grid; ptr->LayerGroups = Settings.LayerGroups; STYLE_LOOP (ptr); { *style = Settings.RouteStyle[n]; style->index = n; } END_LOOP; ptr->MaxWidth = Settings.MaxWidth; ptr->MaxHeight = Settings.MaxHeight; ptr->ID = ID++; ptr->ThermScale = 0.5; ptr->Bloat = Settings.Bloat; ptr->Shrink = Settings.Shrink; ptr->minWid = Settings.minWid; ptr->minSlk = Settings.minSlk; ptr->minDrill = Settings.minDrill; ptr->minRing = Settings.minRing; for (i = 0; i < MAX_LAYER; i++) ptr->Data->Layer[i].Name = strdup (Settings.DefaultLayerName[i]); CreateDefaultFont (ptr); return (ptr); } /*! * \brief This post-processing step adds the top and bottom silk layers * to a pre-existing PCB. * * Called after PCB->Data->LayerN is set. * * \return Returns zero if no errors, else nonzero. */ int CreateNewPCBPost (PCBType *pcb, int use_defaults) { /* copy default settings */ pcb_colors_from_settings (pcb); if (use_defaults) { if (ParseGroupString (Settings.Groups, &pcb->LayerGroups, &pcb->Data->LayerN)) return 1; } pcb->Data->Layer[top_silk_layer].Name = strdup ("top silk"); pcb->Data->Layer[top_silk_layer].Type = LT_SILK; pcb->Data->Layer[bottom_silk_layer].Name = strdup ("bottom silk"); pcb->Data->Layer[bottom_silk_layer].Type = LT_SILK; return 0; } /*! * \brief Creates a new via. */ PinType * CreateNewVia (DataType *Data, Coord X, Coord Y, Coord Thickness, Coord Clearance, Coord Mask, Coord DrillingHole, char *Name, FlagType Flags) { PinType *Via; if (!be_lenient) { VIA_LOOP (Data); { if (Distance (X, Y, via->X, via->Y) <= via->DrillingHole / 2 + DrillingHole / 2) { Message (_("%m+Dropping via at %$mD because it's hole would overlap with the via " "at %$mD\n"), Settings.grid_unit->allow, X, Y, via->X, via->Y); return (NULL); /* don't allow via stacking */ } } END_LOOP; } Via = GetViaMemory (Data); if (!Via) return (Via); /* copy values */ Via->X = X; Via->Y = Y; Via->Thickness = Thickness; Via->Clearance = Clearance; Via->Mask = Mask; Via->DrillingHole = vendorDrillMap (DrillingHole); if (Via->DrillingHole != DrillingHole) { Message (_("%m+Mapped via drill hole to %$mS from %$mS per vendor table\n"), Settings.grid_unit->allow, Via->DrillingHole, DrillingHole); } Via->Name = STRDUP (Name); Via->Flags = Flags; Via->BuriedFrom = 0; Via->BuriedTo = 0; CLEAR_FLAG (WARNFLAG, Via); SET_FLAG (VIAFLAG, Via); Via->ID = ID++; /* Increase copper diameter to drill hole size if it's lower (unless it's a mounting hole). This will at least make incrementing the via's copper size reasonably intuitive (i.e. it won't take several increments before the copper is visible). */ if (!TEST_FLAG (HOLEFLAG, Via) && (Via->Thickness < Via->DrillingHole)) { Via->Thickness = Via->DrillingHole; Message (_("%m+Warning: Via's pad diameter was below hole size, " "so pad diameter was increased to hole size at %$mD.\n"), Settings.grid_unit->allow, Via->X, Via->Y); } SetPinBoundingBox (Via); if (!Data->via_tree) Data->via_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Data->via_tree, (BoxType *) Via, 0); return (Via); } /*! * * \brief Creates a new via with buried info. * */ PinType * CreateNewViaEx (DataType *Data, Coord X, Coord Y, Coord Thickness, Coord Clearance, Coord Mask, Coord DrillingHole, char *Name, FlagType Flags, Cardinal buried_from, Cardinal buried_to) { PinType *Via; Via = CreateNewVia (Data, X, Y, Thickness, Clearance, Mask, DrillingHole, Name, Flags); if (Via) { if (buried_from == buried_to) { Via->BuriedFrom = 0; Via->BuriedTo = 0; } else if (buried_from <= buried_to) { Via->BuriedFrom = buried_from; Via->BuriedTo = buried_to; } else { Via->BuriedFrom = buried_to; Via->BuriedTo = buried_from; } } return Via; } struct line_info { Coord X1, X2, Y1, Y2; Coord Thickness; Coord Clearance; FlagType Flags; LineType test, *ans; jmp_buf env; }; static int line_callback (const BoxType * b, void *cl) { LineType *line = (LineType *) b; struct line_info *i = (struct line_info *) cl; if (line->Point1.X == i->X1 && line->Point2.X == i->X2 && line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2) { i->ans = (LineType *) (-1); longjmp (i->env, 1); } /* check the other point order */ if (line->Point1.X == i->X1 && line->Point2.X == i->X2 && line->Point1.Y == i->Y1 && line->Point2.Y == i->Y2) { i->ans = (LineType *) (-1); longjmp (i->env, 1); } if (line->Point2.X == i->X1 && line->Point1.X == i->X2 && line->Point2.Y == i->Y1 && line->Point1.Y == i->Y2) { i->ans = (LineType *) - 1; longjmp (i->env, 1); } /* remove unnecessary line points */ if (line->Thickness == i->Thickness && /* don't merge lines if the clearances differ */ line->Clearance == i->Clearance && /* don't merge lines if the clear flags differ */ TEST_FLAG (CLEARLINEFLAG, line) == TEST_FLAG (CLEARLINEFLAG, i)) { if (line->Point1.X == i->X1 && line->Point1.Y == i->Y1) { i->test.Point1.X = line->Point2.X; i->test.Point1.Y = line->Point2.Y; i->test.Point2.X = i->X2; i->test.Point2.Y = i->Y2; if (IsPointOnLine (i->X1, i->Y1, 0.0, &i->test)) { i->ans = line; longjmp (i->env, 1); } } else if (line->Point2.X == i->X1 && line->Point2.Y == i->Y1) { i->test.Point1.X = line->Point1.X; i->test.Point1.Y = line->Point1.Y; i->test.Point2.X = i->X2; i->test.Point2.Y = i->Y2; if (IsPointOnLine (i->X1, i->Y1, 0.0, &i->test)) { i->ans = line; longjmp (i->env, 1); } } else if (line->Point1.X == i->X2 && line->Point1.Y == i->Y2) { i->test.Point1.X = line->Point2.X; i->test.Point1.Y = line->Point2.Y; i->test.Point2.X = i->X1; i->test.Point2.Y = i->Y1; if (IsPointOnLine (i->X2, i->Y2, 0.0, &i->test)) { i->ans = line; longjmp (i->env, 1); } } else if (line->Point2.X == i->X2 && line->Point2.Y == i->Y2) { i->test.Point1.X = line->Point1.X; i->test.Point1.Y = line->Point1.Y; i->test.Point2.X = i->X1; i->test.Point2.Y = i->Y1; if (IsPointOnLine (i->X2, i->Y2, 0.0, &i->test)) { i->ans = line; longjmp (i->env, 1); } } } return 0; } /*! * \brief Creates a new line on a layer and checks for overlap and * extension. */ LineType * CreateDrawnLineOnLayer (LayerType *Layer, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness, Coord Clearance, FlagType Flags) { struct line_info info; BoxType search; search.X1 = MIN (X1, X2); search.X2 = MAX (X1, X2); search.Y1 = MIN (Y1, Y2); search.Y2 = MAX (Y1, Y2); if (search.Y2 == search.Y1) search.Y2++; if (search.X2 == search.X1) search.X2++; info.X1 = X1; info.X2 = X2; info.Y1 = Y1; info.Y2 = Y2; info.Thickness = Thickness; info.Clearance = Clearance; info.Flags = Flags; info.test.Thickness = 0; info.test.Flags = NoFlags (); info.ans = NULL; /* prevent stacking of duplicate lines * and remove needless intermediate points * verify that the layer is on the board first! */ if (setjmp (info.env) == 0) { r_search (Layer->line_tree, &search, NULL, line_callback, &info); return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2, Thickness, Clearance, Flags); } if ((void *) info.ans == (void *) (-1)) return NULL; /* stacked line */ /* remove unnecessary points */ if (info.ans) { /* must do this BEFORE getting new line memory */ MoveObjectToRemoveUndoList (LINE_TYPE, Layer, info.ans, info.ans); X1 = info.test.Point1.X; X2 = info.test.Point2.X; Y1 = info.test.Point1.Y; Y2 = info.test.Point2.Y; } return CreateNewLineOnLayer (Layer, X1, Y1, X2, Y2, Thickness, Clearance, Flags); } LineType * CreateNewLineOnLayer (LayerType *Layer, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness, Coord Clearance, FlagType Flags) { LineType *Line; Line = GetLineMemory (Layer); if (!Line) return (Line); Line->ID = ID++; Line->Flags = Flags; CLEAR_FLAG (RATFLAG, Line); Line->Thickness = Thickness; Line->Clearance = Clearance; Line->Point1.X = X1; Line->Point1.Y = Y1; Line->Point1.ID = ID++; Line->Point2.X = X2; Line->Point2.Y = Y2; Line->Point2.ID = ID++; SetLineBoundingBox (Line); if (!Layer->line_tree) Layer->line_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->line_tree, (BoxType *) Line, 0); return (Line); } /*! * \brief Creates a new rat-line. */ RatType * CreateNewRat (DataType *Data, Coord X1, Coord Y1, Coord X2, Coord Y2, Cardinal group1, Cardinal group2, Coord Thickness, FlagType Flags) { RatType *Line = GetRatMemory (Data); if (!Line) return (Line); Line->ID = ID++; Line->Flags = Flags; SET_FLAG (RATFLAG, Line); Line->Thickness = Thickness; Line->Point1.X = X1; Line->Point1.Y = Y1; Line->Point1.ID = ID++; Line->Point2.X = X2; Line->Point2.Y = Y2; Line->Point2.ID = ID++; Line->group1 = group1; Line->group2 = group2; SetLineBoundingBox ((LineType *) Line); if (!Data->rat_tree) Data->rat_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Data->rat_tree, &Line->BoundingBox, 0); return (Line); } /*! * \brief Creates a new arc on a layer. */ ArcType * CreateNewArcOnLayer (LayerType *Layer, Coord X1, Coord Y1, Coord width, Coord height, Angle sa, Angle dir, Coord Thickness, Coord Clearance, FlagType Flags) { ArcType *Arc; ARC_LOOP (Layer); { if (arc->X == X1 && arc->Y == Y1 && arc->Width == width && NormalizeAngle (arc->StartAngle) == NormalizeAngle (sa) && arc->Delta == dir) return (NULL); /* prevent stacked arcs */ } END_LOOP; Arc = GetArcMemory (Layer); if (!Arc) return (Arc); Arc->ID = ID++; Arc->Flags = Flags; Arc->Thickness = Thickness; Arc->Clearance = Clearance; Arc->X = X1; Arc->Y = Y1; Arc->Width = width; Arc->Height = height; Arc->StartAngle = sa; Arc->Delta = dir; SetArcBoundingBox (Arc); if (!Layer->arc_tree) Layer->arc_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0); return (Arc); } /*! * \brief Creates a new polygon from the old formats rectangle data. */ PolygonType * CreateNewPolygonFromRectangle (LayerType *Layer, Coord X1, Coord Y1, Coord X2, Coord Y2, FlagType Flags) { PolygonType *polygon = CreateNewPolygon (Layer, Flags); if (!polygon) return (polygon); CreateNewPointInPolygon (polygon, X1, Y1); CreateNewPointInPolygon (polygon, X2, Y1); CreateNewPointInPolygon (polygon, X2, Y2); CreateNewPointInPolygon (polygon, X1, Y2); SetPolygonBoundingBox (polygon); if (!Layer->polygon_tree) Layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->polygon_tree, (BoxType *) polygon, 0); return (polygon); } /*! * \brief Creates a new text on a layer. */ TextType * CreateNewText (LayerType *Layer, FontType *PCBFont, Coord X, Coord Y, unsigned Direction, int Scale, char *TextString, FlagType Flags) { TextType *text; if (TextString == NULL) return NULL; text = GetTextMemory (Layer); if (text == NULL) return NULL; /* copy values, width and height are set by drawing routine * because at this point we don't know which symbols are available */ text->X = X; text->Y = Y; text->Direction = Direction; text->Flags = Flags; text->Scale = Scale; text->TextString = strdup (TextString); /* calculate size of the bounding box */ SetTextBoundingBox (PCBFont, text); text->ID = ID++; if (!Layer->text_tree) Layer->text_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->text_tree, (BoxType *) text, 0); return (text); } /*! * \brief Creates a new polygon on a layer. */ PolygonType * CreateNewPolygon (LayerType *Layer, FlagType Flags) { PolygonType *polygon = GetPolygonMemory (Layer); /* copy values */ polygon->Flags = Flags; polygon->ID = ID++; polygon->Clipped = NULL; polygon->NoHoles = NULL; polygon->NoHolesValid = 0; return (polygon); } /*! * \brief Creates a new point in a polygon. */ PointType * CreateNewPointInPolygon (PolygonType *Polygon, Coord X, Coord Y) { PointType *point = GetPointMemoryInPolygon (Polygon); /* copy values */ point->X = X; point->Y = Y; point->ID = ID++; return (point); } /*! * \brief Creates a new hole in a polygon. */ PolygonType * CreateNewHoleInPolygon (PolygonType *Polygon) { Cardinal *holeindex = GetHoleIndexMemoryInPolygon (Polygon); *holeindex = Polygon->PointN; return Polygon; } /*! * \brief Creates an new element. * * \note Memory is allocated if needed. */ ElementType * CreateNewElement (DataType *Data, FontType *PCBFont, FlagType Flags, char *Description, char *NameOnPCB, char *Value, Coord TextX, Coord TextY, BYTE Direction, int TextScale, FlagType TextFlags, bool uniqueName) { ElementType *Element; #ifdef DEBUG_CREATE_C printf("Entered CreateNewElement.....\n"); #endif Element = GetElementMemory (Data); /* copy values and set additional information */ TextScale = MAX (MIN_TEXTSCALE, TextScale); AddTextToElement (&DESCRIPTION_TEXT (Element), PCBFont, TextX, TextY, Direction, Description, TextScale, TextFlags); if (uniqueName) NameOnPCB = UniqueElementName (Data, NameOnPCB); AddTextToElement (&NAMEONPCB_TEXT (Element), PCBFont, TextX, TextY, Direction, NameOnPCB, TextScale, TextFlags); AddTextToElement (&VALUE_TEXT (Element), PCBFont, TextX, TextY, Direction, Value, TextScale, TextFlags); DESCRIPTION_TEXT (Element).Element = Element; NAMEONPCB_TEXT (Element).Element = Element; VALUE_TEXT (Element).Element = Element; Element->Flags = Flags; Element->ID = ID++; #ifdef DEBUG_CREATE_C printf(" .... Leaving CreateNewElement.\n"); #endif return (Element); } /*! * \brief Creates a new arc in an element. */ ArcType * CreateNewArcInElement (ElementType *Element, Coord X, Coord Y, Coord Width, Coord Height, Angle angle, Angle delta, Coord Thickness) { ArcType *arc; arc = g_slice_new0 (ArcType); Element->Arc = g_list_append (Element->Arc, arc); Element->ArcN ++; /* set Delta (0,360], StartAngle in [0,360) */ if (delta < 0) { delta = -delta; angle -= delta; } angle = NormalizeAngle (angle); delta = NormalizeAngle (delta); if (delta == 0) delta = 360; /* copy values */ arc->X = X; arc->Y = Y; arc->Width = Width; arc->Height = Height; arc->StartAngle = angle; arc->Delta = delta; arc->Thickness = Thickness; arc->ID = ID++; return arc; } /*! * \brief Creates a new line for an element. */ LineType * CreateNewLineInElement (ElementType *Element, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness) { LineType *line; if (Thickness == 0) return NULL; line = g_slice_new0 (LineType); Element->Line = g_list_append (Element->Line, line); Element->LineN ++; /* copy values */ line->Point1.X = X1; line->Point1.Y = Y1; line->Point2.X = X2; line->Point2.Y = Y2; line->Thickness = Thickness; line->Flags = NoFlags (); line->ID = ID++; return line; } /*! * \brief Creates a new pin in an element. */ PinType * CreateNewPin (ElementType *Element, Coord X, Coord Y, Coord Thickness, Coord Clearance, Coord Mask, Coord DrillingHole, char *Name, char *Number, FlagType Flags) { PinType *pin = GetPinMemory (Element); /* copy values */ pin->X = X; pin->Y = Y; pin->Thickness = Thickness; pin->Clearance = Clearance; pin->Mask = Mask; pin->Name = STRDUP (Name); pin->Number = STRDUP (Number); pin->Flags = Flags; CLEAR_FLAG (WARNFLAG, pin); SET_FLAG (PINFLAG, pin); pin->ID = ID++; pin->Element = Element; /* * If there is no vendor drill map installed, this will simply * return DrillingHole. */ pin->DrillingHole = vendorDrillMap (DrillingHole); /* Unless we should not map drills on this element, map them! */ if (vendorIsElementMappable (Element)) { if (pin->DrillingHole < MIN_PINORVIASIZE) { Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS is below the minimum allowed size\n"), Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole); pin->DrillingHole = DrillingHole; } else if (pin->DrillingHole > MAX_PINORVIASIZE) { Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS is above the maximum allowed size\n"), Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole); pin->DrillingHole = DrillingHole; } else if (!TEST_FLAG (HOLEFLAG, pin) && (pin->DrillingHole > pin->Thickness)) { Message (_("%m+Did not map pin #%s (%s) drill hole because %$mS does not leave any copper\n"), Settings.grid_unit->allow, UNKNOWN (Number), UNKNOWN (Name), pin->DrillingHole); pin->DrillingHole = DrillingHole; } } else { pin->DrillingHole = DrillingHole; } if (pin->DrillingHole != DrillingHole) { Message (_("%m+Mapped pin drill hole to %$mS from %$mS per vendor table\n"), Settings.grid_unit->allow, pin->DrillingHole, DrillingHole); } return (pin); } /*! * \brief Creates a new pad in an element. */ PadType * CreateNewPad (ElementType *Element, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness, Coord Clearance, Coord Mask, char *Name, char *Number, FlagType Flags) { PadType *pad = GetPadMemory (Element); /* copy values */ if (X1 > X2 || (X1 == X2 && Y1 > Y2)) { pad->Point1.X = X2; pad->Point1.Y = Y2; pad->Point2.X = X1; pad->Point2.Y = Y1; } else { pad->Point1.X = X1; pad->Point1.Y = Y1; pad->Point2.X = X2; pad->Point2.Y = Y2; } pad->Thickness = Thickness; pad->Clearance = Clearance; pad->Mask = Mask; pad->Name = STRDUP (Name); pad->Number = STRDUP (Number); pad->Flags = Flags; CLEAR_FLAG (WARNFLAG, pad); pad->ID = ID++; pad->Element = Element; return (pad); } /*! * \brief Creates a new textobject as part of an element. * * Copies the values to the appropriate text object. */ static void AddTextToElement (TextType *Text, FontType *PCBFont, Coord X, Coord Y, unsigned Direction, char *TextString, int Scale, FlagType Flags) { free (Text->TextString); Text->TextString = (TextString && *TextString) ? strdup (TextString) : NULL; Text->X = X; Text->Y = Y; Text->Direction = Direction; Text->Flags = Flags; Text->Scale = Scale; /* calculate size of the bounding box */ SetTextBoundingBox (PCBFont, Text); Text->ID = ID++; } /*! * \brief Creates a new line in a symbol. */ LineType * CreateNewLineInSymbol (SymbolType *Symbol, Coord X1, Coord Y1, Coord X2, Coord Y2, Coord Thickness) { LineType *line = Symbol->Line; /* realloc new memory if necessary and clear it */ if (Symbol->LineN >= Symbol->LineMax) { Symbol->LineMax += STEP_SYMBOLLINE; line = (LineType *)realloc (line, Symbol->LineMax * sizeof (LineType)); Symbol->Line = line; memset (line + Symbol->LineN, 0, STEP_SYMBOLLINE * sizeof (LineType)); } /* copy values */ line = line + Symbol->LineN++; line->Point1.X = X1; line->Point1.Y = Y1; line->Point2.X = X2; line->Point2.Y = Y2; line->Thickness = Thickness; return (line); } /*! * \brief Parses a file with font information and installs it into the * provided PCB. * * Checks directories given as colon separated list by resource fontPath * if the fonts filename doesn't contain a directory component. */ void CreateDefaultFont (PCBType *pcb) { if (ParseFont (&pcb->Font, Settings.FontFile)) Message (_("Can't find font-symbol-file '%s'\n"), Settings.FontFile); } /*! * \brief Adds a new line to the rubberband list of * 'Crosshair.AttachedObject'. * * If Layer == 0 it is a rat line. */ RubberbandType * CreateNewRubberbandEntry (LayerType *Layer, LineType *Line, PointType *MovedPoint) { RubberbandType *ptr = GetRubberbandMemory (); /* we toggle the RUBBERENDFLAG of the line to determine if */ /* both points are being moved. */ TOGGLE_FLAG (RUBBERENDFLAG, Line); ptr->Layer = Layer; ptr->Line = Line; ptr->MovedPoint = MovedPoint; return (ptr); } /*! * \brief Add a new net to the netlist menu. */ LibraryMenuType * CreateNewNet (LibraryType *lib, char *name, char *style) { LibraryMenuType *menu; char temp[64]; sprintf (temp, " %s", name); menu = GetLibraryMenuMemory (lib); menu->Name = strdup (temp); menu->flag = 1; /* net is enabled by default */ if (style == NULL || NSTRCMP ("(unknown)", style) == 0) menu->Style = NULL; else menu->Style = strdup (style); return (menu); } /*! * \brief Add a connection to the net. */ LibraryEntryType * CreateNewConnection (LibraryMenuType *net, char *conn) { LibraryEntryType *entry = GetLibraryEntryMemory (net); entry->ListEntry = STRDUP (conn); return (entry); } /*! * \brief Add an attribute to a list.. */ AttributeType * CreateNewAttribute (AttributeListType *list, char *name, char *value) { if (list->Number >= list->Max) { list->Max += 10; list->List = (AttributeType *)realloc (list->List, list->Max * sizeof (AttributeType)); } list->List[list->Number].name = STRDUP (name); list->List[list->Number].value = STRDUP (value); list->Number++; return &list->List[list->Number - 1]; } /* * Actions */ static const char create_via_syntax[] = N_("CreateVia(x,y,[unit])\n"); static const char create_via_help[] = N_("Add a via to the board."); static int create_via_action(int argc, char **argv, Coord x, Coord y) { char *x_str = ARG (0); char *y_str = ARG (1); char *units = ARG (2); Coord nx, ny; bool absolute1, absolute2; PinType *via; ny = GetValue (y_str, units, &absolute1); nx = GetValue (x_str, units, &absolute2); if (!absolute1 || !absolute2) { Message( "CreateVia action does not currently support relative placements.\n"); } via = CreateNewVia(PCB->Data, nx, ny, Settings.ViaThickness, 2*Settings.Keepaway, Settings.ViaMaskAperture, Settings.ViaDrillingHole, NULL, NoFlags()); return via->ID; } static HID_Action create_action_list[] = { {"CreateVia", NULL, create_via_action, create_via_help, create_via_syntax} }; REGISTER_ACTIONS (create_action_list) pcb-4.2.2/src/hid_draw.h0000664000076400007640000001053413533277055011754 00000000000000/*! * \file src/hid_draw.h * * \brief Human Interface Device - Drawing. *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu */ /*! * \brief Mask modes. */ enum mask_mode { HID_MASK_OFF = 0, /*!< Flush the buffer and return to non-mask operation. */ HID_MASK_BEFORE = 1, /*!< Polygons being drawn before clears. */ HID_MASK_CLEAR = 2, /*!< Clearances being drawn. */ HID_MASK_AFTER = 3, /*!< Polygons being drawn after clears. */ }; /*! * \brief Low level drawing API Drawing Functions. * * Coordinates and distances are ALWAYS in PCB's default coordinates * (1 nm at the time this comment was written). * * Angles are always in degrees, with 0 being "right" (positive X) and * 90 being "up" (positive Y). */ struct hid_draw_st { hidGC (*make_gc) (void); /*!< Make an empty graphics context. */ void (*destroy_gc) (hidGC gc); void (*use_mask) (enum mask_mode mode); void (*set_color) (hidGC gc, const char *name); /*!< Set a color. Names can be like "red" or "#rrggbb" or special * names like "erase". * *Always* use the "erase" color for removing ink (like polygon * reliefs or thermals), as you cannot rely on knowing the background * color or special needs of the HID. * Always use the "drill" color to draw holes. * You may assume this is cheap enough to call inside the redraw * callback, but not cheap enough to call for each item drawn. */ void (*set_line_cap) (hidGC gc, EndCapStyle style); /*!< Set the line style. While calling this is cheap, calling it with * different values each time may be expensive, so grouping items by * line style is helpful. */ void (*set_line_width) (hidGC gc, Coord width); void (*set_draw_xor) (hidGC gc, int xor_); void (*set_draw_faded) (hidGC gc, int faded); /*!< Blends 20% or so color with 80% background. * Only used for assembly drawings so far. */ /* The usual drawing functions. "draw" means to use segments of the given width, whereas "fill" means to fill to a zero-width outline. */ void (*draw_line) (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); void (*draw_arc) (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius, Angle start_angle, Angle delta_angle); void (*draw_rect) (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); void (*fill_circle) (hidGC gc, Coord cx, Coord cy, Coord radius); void (*fill_polygon) (hidGC gc, int n_coords, Coord *x, Coord *y); void (*fill_rect) (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); /* draw the grid in the specified region */ void (*draw_grid) (BoxType * box); /* The following APIs render using PCB data-structures, not immediate parameters */ void (*draw_pcb_line) (hidGC gc, LineType *line); void (*draw_pcb_arc) (hidGC gc, ArcType *arc); void (*draw_pcb_text) (hidGC gc, TextType *, Coord); void (*draw_pcb_polygon) (hidGC gc, PolygonType *poly, const BoxType *clip_box); void (*fill_pcb_polygon) (hidGC gc, PolygonType *poly, const BoxType *clip_box); void (*thindraw_pcb_polygon) (hidGC gc, PolygonType *poly, const BoxType *clip_box); void (*fill_pcb_pad) (hidGC gc, PadType *pad, bool clip, bool mask); void (*thindraw_pcb_pad) (hidGC gc, PadType *pad, bool clip, bool mask); void (*fill_pcb_pv) (hidGC fg_gc, hidGC bg_gc, PinType *pv, bool drawHole, bool mask); void (*thindraw_pcb_pv) (hidGC fg_gc, hidGC bg_gc, PinType *pv, bool drawHole, bool mask); }; pcb-4.2.2/src/action.h0000664000076400007640000000262313434555140011442 00000000000000/*! * \file src/action.h * * \brief Prototypes for action routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_ACTION_H #define PCB_ACTION_H #include "global.h" #define CLONE_TYPES LINE_TYPE | ARC_TYPE | VIA_TYPE | POLYGON_TYPE void ActionAdjustStyle (char *); void EventMoveCrosshair (int, int); void AdjustAttachedObjects (void); void warpNoWhere (void); /* In gui-misc.c */ bool ActionGetLocation (char *); void ActionGetXY (char *); #endif pcb-4.2.2/src/netlist.c0000664000076400007640000003001413533277055011643 00000000000000/*! * \file src/netlist.c * * \brief Generic netlist operations. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996, 2005 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef HAVE_STRING_H #include #endif #include #include #ifdef HAVE_REGEX_H #include #endif #include "global.h" #include "action.h" #include "buffer.h" #include "data.h" #include "djopt.h" #include "error.h" #include "file.h" #include "find.h" #include "mymem.h" #include "misc.h" #include "rats.h" #include "set.h" #include "vendor.h" #include "create.h" #ifdef HAVE_REGCOMP #undef HAVE_RE_COMP #endif #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) #define USE_RE #endif #ifdef HAVE_LIBDMALLOC #include #endif /* int PCB->NetlistLib.MenuN char * PCB->NetlistLib.Menu[i].Name [0] == '*' (ok for rats) or ' ' (skip for rats) [1] == unused [2..] actual name char * PCB->NetlistLib.Menu[i].Style int PCB->NetlistLib.Menu[i].EntryN char * PCB->NetlistLib.Menu[i].Entry[j].ListEntry */ typedef void (*NFunc) (LibraryMenuType *, LibraryEntryType *); int netlist_frozen = 0; static int netlist_needs_update = 0; void NetlistChanged (int force_unfreeze) { if (force_unfreeze) netlist_frozen = 0; if (netlist_frozen) netlist_needs_update = 1; else { netlist_needs_update = 0; hid_action ("NetlistChanged"); } } LibraryMenuType * netnode_to_netname (char *nodename) { int i, j; /*printf("nodename [%s]\n", nodename);*/ for (i=0; iNetlistLib.MenuN; i++) { for (j=0; jNetlistLib.Menu[i].EntryN; j++) { if (strcmp (PCB->NetlistLib.Menu[i].Entry[j].ListEntry, nodename) == 0) { /*printf(" in [%s]\n", PCB->NetlistLib.Menu[i].Name);*/ return & (PCB->NetlistLib.Menu[i]); } } } return 0; } LibraryMenuType * netname_to_netname (char *netname) { int i; if ((netname[0] == '*' || netname[0] == ' ') && netname[1] == ' ') { /* Looks like we were passed an internal netname, skip the prefix */ netname += 2; } for (i=0; iNetlistLib.MenuN; i++) { if (strcmp (PCB->NetlistLib.Menu[i].Name + 2, netname) == 0) { return & (PCB->NetlistLib.Menu[i]); } } return 0; } static int pin_name_to_xy (LibraryEntryType * pin, int *x, int *y) { ConnectionType conn; if (!SeekPad (pin, &conn, false)) return 1; switch (conn.type) { case PIN_TYPE: *x = ((PinType *) (conn.ptr2))->X; *y = ((PinType *) (conn.ptr2))->Y; return 0; case PAD_TYPE: *x = ((PadType *) (conn.ptr2))->Point1.X; *y = ((PadType *) (conn.ptr2))->Point1.Y; return 0; } return 1; } static void netlist_find (LibraryMenuType * net, LibraryEntryType * pin) { int x, y; if (pin_name_to_xy (net->Entry, &x, &y)) return; LookupConnection (x, y, 1, 1, FOUNDFLAG, true); } static void netlist_select (LibraryMenuType * net, LibraryEntryType * pin) { int x, y; if (pin_name_to_xy (net->Entry, &x, &y)) return; LookupConnection (x, y, 1, 1, SELECTEDFLAG, true); } static void netlist_rats (LibraryMenuType * net, LibraryEntryType * pin) { net->Name[0] = ' '; net->flag = 1; NetlistChanged (0); } static void netlist_norats (LibraryMenuType * net, LibraryEntryType * pin) { net->Name[0] = '*'; net->flag = 0; NetlistChanged (0); } /*! * \brief The primary purpose of this action is to remove the netlist * completely so that a new one can be loaded, usually via a gsch2pcb * style script. */ static void netlist_clear (LibraryMenuType * net, LibraryEntryType * pin) { LibraryType *netlist = &PCB->NetlistLib; int ni, pi; if (net == 0) { /* Clear the entire netlist. */ FreeLibraryMemory (&PCB->NetlistLib); } else if (pin == 0) { /* Remove a net from the netlist. */ ni = net - netlist->Menu; if (ni >= 0 && ni < netlist->MenuN) { /* if there is exactly one item, MenuN is 1 and ni is 0 */ if (netlist->MenuN - ni > 1) memmove (net, net+1, (netlist->MenuN - ni - 1) * sizeof (*net)); netlist->MenuN --; } } else { /* Remove a pin from the given net. Note that this may leave an empty net, which is different than removing the net (above). */ pi = pin - net->Entry; if (pi >= 0 && pi < net->EntryN) { /* if there is exactly one item, MenuN is 1 and ni is 0 */ if (net->EntryN - pi > 1) memmove (pin, pin+1, (net->EntryN - pi - 1) * sizeof (*pin)); net->EntryN --; } } NetlistChanged (0); } static void netlist_style (LibraryMenuType *net, const char *style) { free (net->Style); net->Style = STRDUP ((char *)style); } /*! * \brief The primary purpose of this action is to rebuild a netlist * from a script, in conjunction with the clear action above. */ static int netlist_add (const char *netname, const char *pinname) { int ni, pi; LibraryType *netlist = &PCB->NetlistLib; LibraryMenuType *net = NULL; LibraryEntryType *pin = NULL; for (ni=0; niMenuN; ni++) if (strcmp (netlist->Menu[ni].Name+2, netname) == 0) { net = & (netlist->Menu[ni]); break; } if (net == NULL) { net = CreateNewNet (netlist, (char *)netname, NULL); } for (pi=0; piEntryN; pi++) if (strcmp (net->Entry[pi].ListEntry, pinname) == 0) { pin = & (net->Entry[pi]); break; } if (pin == NULL) { pin = CreateNewConnection (net, (char *)pinname); } NetlistChanged (0); return 0; } static const char netlist_syntax[] = "Net(find|select|rats|norats|clear[,net[,pin]])\n" "Net(freeze|thaw|forcethaw)\n" "Net(add,net,pin)"; static const char netlist_help[] = "Perform various actions on netlists."; /* %start-doc actions Netlist Each of these actions apply to a specified set of nets. @var{net} and @var{pin} are patterns which match one or more nets or pins; these patterns may be full names or regular expressions. If an exact match is found, it is the only match; if no exact match is found, @emph{then} the pattern is tried as a regular expression. If neither @var{net} nor @var{pin} are specified, all nets apply. If @var{net} is specified but not @var{pin}, all nets matching @var{net} apply. If both are specified, nets which match @var{net} and contain a pin matching @var{pin} apply. @table @code @item find Nets which apply are marked @emph{found} and are drawn in the @code{connected-color} color. @item select Nets which apply are selected. @item rats Nets which apply are marked as available for the rats nest. @item norats Nets which apply are marked as not available for the rats nest. @item clear Clears the netlist. @item add Add the given pin to the given netlist, creating either if needed. @item sort Called after a list of add's, this sorts the netlist. @item freeze @itemx thaw @itemx forcethaw Temporarily prevents changes to the netlist from being reflected in the GUI. For example, if you need to make multiple changes, you freeze the netlist, make the changes, then thaw it. Note that freeze/thaw requests may nest, with the netlist being fully thawed only when all pending freezes are thawed. You can bypass the nesting by using forcethaw, which resets the freeze count and immediately updates the GUI. @end table %end-doc */ static int Netlist (int argc, char **argv, Coord x, Coord y) { NFunc func; int i, j; LibraryMenuType *net; LibraryEntryType *pin; int net_found = 0; int pin_found = 0; #if defined(USE_RE) int use_re = 0; #endif #if defined(HAVE_REGCOMP) regex_t elt_pattern; regmatch_t match; #endif #if defined(HAVE_RE_COMP) char *elt_pattern; #endif if (!PCB) return 1; if (argc == 0) { Message (netlist_syntax); return 1; } if (strcasecmp (argv[0], "find") == 0) func = netlist_find; else if (strcasecmp (argv[0], "select") == 0) func = netlist_select; else if (strcasecmp (argv[0], "rats") == 0) func = netlist_rats; else if (strcasecmp (argv[0], "norats") == 0) func = netlist_norats; else if (strcasecmp (argv[0], "clear") == 0) { func = netlist_clear; if (argc == 1) { netlist_clear (NULL, NULL); return 0; } } else if (strcasecmp (argv[0], "style") == 0) func = (NFunc)netlist_style; else if (strcasecmp (argv[0], "add") == 0) { /* Add is different, because the net/pin won't already exist. */ return netlist_add (ARG(1), ARG(2)); } else if (strcasecmp (argv[0], "sort") == 0) { sort_netlist (); return 0; } else if (strcasecmp (argv[0], "freeze") == 0) { netlist_frozen ++; return 0; } else if (strcasecmp (argv[0], "thaw") == 0) { if (netlist_frozen > 0) { netlist_frozen --; if (netlist_needs_update) NetlistChanged (0); } return 0; } else if (strcasecmp (argv[0], "forcethaw") == 0) { netlist_frozen = 0; if (netlist_needs_update) NetlistChanged (0); return 0; } else { Message (netlist_syntax); return 1; } #if defined(USE_RE) if (argc > 1) { int result; use_re = 1; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { net = PCB->NetlistLib.Menu + i; if (strcasecmp (argv[1], net->Name + 2) == 0) use_re = 0; } if (use_re) { #if defined(HAVE_REGCOMP) result = regcomp (&elt_pattern, argv[1], REG_EXTENDED | REG_ICASE | REG_NOSUB); if (result) { char errorstring[128]; regerror (result, &elt_pattern, errorstring, 128); Message (_("regexp error: %s\n"), errorstring); regfree (&elt_pattern); return (1); } #endif #if defined(HAVE_RE_COMP) if ((elt_pattern = re_comp (argv[1])) != NULL) { Message (_("re_comp error: %s\n"), elt_pattern); return (false); } #endif } } #endif for (i = PCB->NetlistLib.MenuN-1; i >= 0; i--) { net = PCB->NetlistLib.Menu + i; if (argc > 1) { #if defined(USE_RE) if (use_re) { #if defined(HAVE_REGCOMP) if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0) continue; #endif #if defined(HAVE_RE_COMP) if (re_exec (net->Name + 2) != 1) continue; #endif } else #endif if (strcasecmp (net->Name + 2, argv[1])) continue; } net_found = 1; pin = 0; if (func == (void *)netlist_style) { netlist_style (net, ARG(2)); } else if (argc > 2) { int l = strlen (argv[2]); for (j = net->EntryN-1; j >= 0 ; j--) if (strcasecmp (net->Entry[j].ListEntry, argv[2]) == 0 || (strncasecmp (net->Entry[j].ListEntry, argv[2], l) == 0 && net->Entry[j].ListEntry[l] == '-')) { pin = net->Entry + j; pin_found = 1; func (net, pin); } } else func (net, 0); } if (argc > 2 && !pin_found) { gui->log ("Net %s has no pin %s\n", argv[1], argv[2]); return 1; } else if (!net_found) { gui->log ("No net named %s\n", argv[1]); } #ifdef HAVE_REGCOMP if (use_re) regfree (&elt_pattern); #endif return 0; } HID_Action netlist_action_list[] = { {"net", 0, Netlist, netlist_help, netlist_syntax} , {"netlist", 0, Netlist, netlist_help, netlist_syntax} }; REGISTER_ACTIONS (netlist_action_list) pcb-4.2.2/src/buffer.h0000664000076400007640000000370113434555140011434 00000000000000/*! * \file src/buffer.h * * \brief Prototypes for buffer handling routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_BUFFER_H #define PCB_BUFFER_H #include "global.h" /* --------------------------------------------------------------------------- * prototypes */ void SetBufferBoundingBox (BufferType *); void ClearBuffer (BufferType *); void AddSelectedToBuffer (BufferType *, Coord, Coord, bool); bool LoadElementToBuffer (BufferType *, char *, bool); bool ConvertBufferToElement (BufferType *); bool SmashBufferElement (BufferType *); bool LoadLayoutToBuffer (BufferType *, char *); void RotateBuffer (BufferType *, BYTE); void SelectPasteBuffer (int); void SwapBuffers (void); void MirrorBuffer (BufferType *); void InitBuffers (void); void UninitBuffers (void); void *MoveObjectToBuffer (DataType *, DataType *, int, void *, void *, void *); void *CopyObjectToBuffer (DataType *, DataType *, int, void *, void *, void *); int LoadFootprint (int argc, char **argv, Coord x, Coord y); #endif pcb-4.2.2/src/set.h0000664000076400007640000000310213533277055010757 00000000000000/*! * \file src/set.h * * \brief Prototypes for update routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * */ #ifndef PCB_SET_H #define PCB_SET_H #include "global.h" void SetTextScale (int); void SetGrid (Coord, bool); void SetLineSize (Coord); void SetViaSize (Coord, bool); void SetViaDrillingHole (Coord, bool); void SetViaMaskAperture(Coord); void SetKeepawayWidth (Coord); void SetChangedFlag (bool); void SetBufferNumber (int); void SetMode (int); void SetRouteStyle (char *); void SetLocalRef (Coord, Coord, bool); void SaveMode (void); void RestoreMode (void); void pcb_use_route_style (RouteStyleType *); #endif pcb-4.2.2/src/hid.h0000664000076400007640000006576313533277055010755 00000000000000/*! * \file src/hid.h * * \brief Human Interface Device. * * \author This file, hid.h, was written and is * Copyright (c) 2006 DJ Delorie * * The way the HID layer works is that you instantiate a HID device * structure, and invoke functions through its members. * * Code in the common part of PCB may *not* rely on *anything* other * than what's defined in this file. * * Code in the HID layers *may* rely on data and functions in the common * code (like, board size and such) but it's considered bad form to do * so when not needed. * * Coordinates are ALWAYS in pcb's default resolution. * * Positive X is right, positive Y is down. * * Angles are degrees, with 0 being right (positive X) and 90 being up * (negative Y). * * All zoom, scaling, panning, and conversions are hidden inside the HID * layers. * * The main structure is at the end of this file. * * Data structures passed to the HIDs will be copied if the HID needs to * save them. * * Data structures retured from the HIDs must not be freed, and may be * changed by the HID in response to new information. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu */ #ifndef PCB_HID_H #define PCB_HID_H #include #include "drc/drc_violation.h" /* DrcViolationType */ #if defined(__cplusplus) && __cplusplus extern "C" { #endif /*! * \brief Like end cap styles. * * The cap *always* extends beyond the coordinates given, by half the * width of the line. * * Beveled ends can used to make octagonal pads by giving the same x,y * coordinate twice. */ typedef enum { Trace_Cap, /*!< This means we're drawing a trace, which has round caps. */ Square_Cap, /*!< Square pins or pads. */ Round_Cap, /*!< Round pins or round-ended pads, thermals. */ Beveled_Cap /*!< Octagon pins or bevel-cornered pads. */ } EndCapStyle; /*! * \brief The HID may need something more than an "int" for colors, * timers, etc. * * So it passes/returns one of these, which is castable to a variety * of things. */ typedef union { long lval; void *ptr; } hidval; /*! * This graphics context is an opaque pointer defined by the HID. * * GCs are HID-specific; attempts to use one HID's GC for a different * HID will result in a fatal error. */ typedef struct hid_gc_struct *hidGC; #define HIDCONCAT(a,b) a##b /*! * \brief This is used to register the action callbacks (for menus and * whatnot). * * HID assumes the following actions are available for its use: * - SaveAs(filename); * - Quit(); */ typedef struct { char *name; /*!< This is matched against action names in the GUI configuration */ const char *need_coord_msg; /*!< If this string is non-NULL, the action needs to know the X,Y * coordinates to act on, and this string may be used to prompt * the user to select a coordinate. If NULL, the coordinates may * be 0,0 if none are known. */ int (*trigger_cb) (int argc, char **argv, Coord x, Coord y); /*!< Called when the action is triggered. If this function returns * non-zero, no further actions will be invoked for this key/mouse * event. */ const char *description; /*!< Short description that sometimes accompanies the name. */ const char *syntax; /*!< Full allowed syntax; use \\n to separate lines. */ } HID_Action; extern void hid_register_action (HID_Action *); extern void hid_register_actions (HID_Action *, int); #define REGISTER_ACTIONS(a) HIDCONCAT(void register_,a) ()\ { hid_register_actions(a, sizeof(a)/sizeof(a[0])); } /* Note that PCB expects the gui to provide the following actions: PCBChanged(); RouteStylesChanged() NetlistChanged() (but core should call "void NetlistChanged(int);" in netlist.c) LayersChanged() LibraryChanged() Busy() */ extern const char pcbchanged_help[]; extern const char pcbchanged_syntax[]; extern const char routestyleschanged_help[]; extern const char routestyleschanged_syntax[]; extern const char netlistchanged_help[]; extern const char netlistchanged_syntax[]; extern const char layerschanged_help[]; extern const char layerschanged_syntax[]; extern const char librarychanged_help[]; extern const char librarychanged_syntax[]; int hid_action (const char *action_); int hid_actionl (const char *action_, ...); /* NULL terminated */ int hid_actionv (const char *action_, int argc_, char **argv_); void hid_save_settings (int); void hid_load_settings (void); /*! * \brief Parse the given command string into action calls, and call * hid_actionv for each action found. * * Accepts both "action(arg1, arg2)" and command-style * "action arg1 arg2", allowing only one action in the later case. * * \return Returns nonzero if the action handler(s) return nonzero. */ int hid_parse_command (const char *str_); /*! * \brief Parse the given string into action calls, and call hid_actionv * for each action found. * * Accepts only "action(arg1, arg2)". */ int hid_parse_actions (const char *str_); typedef struct { char *name; /*!< Name of the flag */ int (*function) (void *); /*!< Function to call to get the value of the flag. */ void *parm; /*!< Additional parameter to pass to that function. */ } HID_Flag; extern void hid_register_flags (HID_Flag *, int); #define REGISTER_FLAGS(a) HIDCONCAT(void register_,a) ()\ { hid_register_flags(a, sizeof(a)/sizeof(a[0])); } /*! * \brief Looks up one of the flags registered above. * * \return If the flag is unknown, returns zero. */ int hid_get_flag (const char *name_); /*! * \brief Used for HID attributes (exporting and printing, mostly). * * HA_boolean uses int_value, HA_enum sets int_value to the index and * str_value to the enumeration string. * * HID_Label just shows the default str_value. * * HID_Mixed is a real_value followed by an enum, like 0.5in or 100mm. */ typedef struct { int int_value; const char *str_value; double real_value; Coord coord_value; } HID_Attr_Val; enum hids { HID_Label, HID_Integer, HID_Real, HID_String, HID_Boolean, HID_Enum, HID_Mixed, HID_Path, HID_Unit, HID_Coord }; typedef struct { char *name; #define ATTR_UNDOCUMENTED ((char *)(1)) char *help_text; /*!< If the help_text is this, usage() won't show this option */ enum hids type; int min_val; /*!< For integer and real */ int max_val; /*!< For integer and real */ HID_Attr_Val default_val; /*!< Also actual value for global attributes. */ const char **enumerations; void *value; /*!< If set, this is used for global attributes (i.e. those set * statically with REGISTER_ATTRIBUTES below) instead of changing * the default_val. * \note Note that a HID_Mixed attribute must specify a pointer to * HID_Attr_Val here, and HID_Boolean assumes this is "char *" so * the value should be initialized to zero, and may be set to * non-zero (not always one). */ int hash; /*!< For detecting changes. */ } HID_Attribute; extern void hid_register_attributes (HID_Attribute *, int); #define REGISTER_ATTRIBUTES(a) HIDCONCAT(void register_,a) ()\ { hid_register_attributes(a, sizeof(a)/sizeof(a[0])); } /* These three are set by hid_parse_command_line(). */ extern char *program_name; extern char *program_directory; extern char *program_basename; /* These are used for set_layer(). */ #define SL_0_SIDE 0x0000 #define SL_TOP_SIDE 0x0001 #define SL_BOTTOM_SIDE 0x0002 #define SL_INNER_SIDE 0x0004 /* * These are types of "layers" without direct physical representation. * Their content can be derived from other layers and element data. * * These values are used by DrawEverything() in draw.c to ask the active * GUI or exporter to act on these layers. Depending on the GUI/exporter * they result in a per-layer file, in some additional graphics or just * nothing. */ #define SL_SILK 0x0010 /*!< Physical layer, deprecated, use LT_SILK. */ #define SL_MASK 0x0020 #define SL_PDRILL 0x0030 #define SL_UDRILL 0x0040 #define SL_PASTE 0x0050 #define SL_INVISIBLE 0x0060 #define SL_FAB 0x0070 #define SL_ASSY 0x0080 #define SL_RATS 0x0090 /* Callers should use this. */ #define SL(type,side) (~0xfff | SL_##type | SL_##side##_SIDE) /*! * These are layers with direct physical representation, like copper, dye * or to be milled paths. Their data can't be derived from other layers or * element data. * * To add more layer types, add them to the list here and in layerflags.c. * Order of entries in both lists must be the same. */ typedef enum { LT_COPPER = 0, LT_SILK, LT_MASK, /*!< Complements SL_MASK above. */ LT_PASTE, /*!< Complements SL_PASTE above. */ LT_OUTLINE, /*!< Board outline; exists only once. */ LT_ROUTE, LT_KEEPOUT, LT_FAB, /*!< Complements SL_FAB above. */ LT_ASSY, /*!< Complements SL_ASSY above. */ LT_NOTES, LT_NUM_LAYERTYPES /*!< Must be the last one. */ } LayertypeType; /*! * \brief File Watch flags. * * Based upon those in dbus/dbus-connection.h. */ typedef enum { PCB_WATCH_READABLE = 1 << 0, /*!< As in POLLIN */ PCB_WATCH_WRITABLE = 1 << 1, /*!< As in POLLOUT */ PCB_WATCH_ERROR = 1 << 2, /*!< As in POLLERR */ PCB_WATCH_HANGUP = 1 << 3 /*!< As in POLLHUP */ } PCBWatchFlags; /*! * \brief DRC GUI Hooks. */ typedef struct { int log_drc_overview; int log_drc_violations; void (*reset_drc_dialog_message) (void); void (*append_drc_violation) (DrcViolationType *violation); int (*throw_drc_dialog) (void); } HID_DRC_GUI; typedef struct hid_st HID; typedef struct hid_draw_st HID_DRAW; /*! * \brief This is the main HID structure. */ struct hid_st { int struct_size; /*!< The size of this structure. * * We use this as a compatibility check; a HID built with a * different hid.h than we're expecting should have a different * size here. */ const char *name; /*!< The name of this HID. * * This should be suitable for command line options, * multi-selection menus, file names, etc. */ const char *description; /*!< Likewise, but allowed to be longer and more descriptive. */ char gui:1; /*!< If set, this is the GUI HID. * * Exactly one of these three flags must be set; setting "gui" * lets the expose callback optimize and coordinate itself. */ char printer:1; /*!< If set, this is the printer-class HID. * * The common part of PCB may use this to do command-line printing, * without having instantiated any GUI HIDs. * Only one printer HID is normally defined at a time. */ char exporter:1; /*!< If set, this HID provides an export option, and should be * used as part of the File->Export menu option. * * Examples are PNG, Gerber, and EPS exporters. */ char poly_before:1; /*!< If set, the redraw code will draw polygons before erasing the * clearances. */ char poly_after:1; /*!< If set, the redraw code will draw polygons after erasing the * clearances. * * \note Note that HIDs may set both of these, in which case * polygons will be drawn twice. */ HID_Attribute *(*get_export_options) (int *n_ret_); /*!< Returns a set of resources describing options the export or * print HID supports. * * In GUI mode, the print/export dialogs use this to set up the * selectable options. * * In command line mode, these are used to interpret command line * options. * * If \c n_ret_ is non-NULL, the number of attributes is stored * there. */ void (*do_export) (HID_Attr_Val * options_); /*!< Export (or print) the current PCB. * * The options given represent the choices made from the options * returned from get_export_options. * * Call with options == NULL to start the primary GUI (create a * main window, print, export, etc). */ void (*uninit) (HID *hid); /*!< uninit a GUI hid. */ void (*do_exit) (HID *hid); /*!< uninit a GUI hid. */ void (*parse_arguments) (int *argc_, char ***argv_); /*!< Parse the command line. * * Call this early for whatever HID will be the primary HID, as it * will set all the registered attributes. * * The HID should remove all arguments, leaving any possible file * names behind. */ void (*invalidate_lr) (Coord left_, Coord right_, Coord top_, Coord bottom_); /*!< This may be called to ask the GUI to force a redraw of a * given area. */ void (*invalidate_all) (void); void (*notify_crosshair_change) (bool changes_complete); void (*notify_mark_change) (bool changes_complete); int (*set_layer) (const char *name_, int group_, int _empty); /*!< During redraw or print/export cycles, this is called once per * layer (or layer group, for copper layers). * * If it returns false (zero), the HID does not want that layer, * and none of the drawing functions should be called. * * If it returns true (nonzero), the items in that layer [group] * should be drawn using the various drawing functions. * * In addition to the MAX_GROUP copper layer groups, you may * select layers indicated by the macros SL_* defined above, or * any others with an index of -1. * * For copper layer groups, you may pass NULL for name to have a * name fetched from the PCB struct. * * The EMPTY argument is a hint - if set, the layer is empty, if * zero it may be non-empty. */ void (*end_layer) (void); /*!< Tell the GUI the layer last selected has been finished with. */ HID_DRAW *graphics; void (*calibrate) (double xval_, double yval_); /*!< This is for the printer. * * If you call this for the GUI, \c xval_ and \c yval_ are ignored, * and a dialog pops up to lead you through the calibration * procedure. * * For the printer, if \c xval_ and \c yval_ are zero, a * calibration page is printed with instructions for calibrating * your printer. * * After calibrating, nonzero \c xval_ and \c yval_ are passed * according to the instructions. * * Metric is nonzero if the user prefers metric units, else inches * are used. */ /* GUI layout functions. Not used or defined for print/export HIDs. */ /* Temporary */ int (*shift_is_pressed) (void); int (*control_is_pressed) (void); int (*mod1_is_pressed) (void); void (*get_coords) (const char *msg_, Coord *x_, Coord *y_); void (*set_crosshair) (int x_, int y_, int cursor_action_); /*!< Sets the crosshair, which may differ from the pointer * depending on grid and pad snap. * * \note Note that the HID is responsible for hiding, showing, * redrawing, etc. The core just tells it what coordinates it's * actually using. * * \note Note that this routine may need to know what "pcb units" * are so it can display them in mm or mils accordingly. * * If \c cursor_action_ is set, the cursor or screen may be * adjusted so that the cursor and the crosshair are at the same * point on the screen. */ #define HID_SC_DO_NOTHING 0 #define HID_SC_WARP_POINTER 1 #define HID_SC_PAN_VIEWPORT 2 #define HID_SC_CENTER_IN_VIEWPORT 3 #define HID_SC_CENTER_IN_VIEWPORT_AND_WARP_POINTER 4 hidval (*add_timer) (void (*func) (hidval user_data_), unsigned long milliseconds_, hidval user_data_); /*!< Causes func to be called at some point in the future. * * Timers are only good for *one* call; if you want it to * repeat, add another timer during the callback for the first. * * \c user_data can be anything, it's just passed to func. * * \warning Times are not guaranteed to be accurate. */ void (*stop_timer) (hidval timer_); /*!< Use this to stop a timer that hasn't triggered yet. */ hidval (*watch_file) (int fd_, unsigned int condition_, void (*func_) (hidval watch_, int fd_, unsigned int condition_, hidval user_data_), hidval user_data); /*!< Causes \c func_ to be called when some condition occurs on * the file descriptor passed. * * Conditions include data for reading, writing, hangup, and * errors. * * \c user_data can be anything, it's just passed to \c func_. */ void (*unwatch_file) (hidval watch_); /*!< Use this to stop a file watch. */ hidval (*add_block_hook) (void (*func_) (hidval data_), hidval data_); /*!< Causes \c func to be called in the main loop prior to * blocking. */ void (*stop_block_hook) (hidval block_hook_); /*!< Use this to stop a main loop block hook. */ /* Various dialogs */ void (*log) (const char *fmt_, ...); /*!< Log a message to the log window. */ void (*logv) (const char *fmt_, va_list args_); /*!< Log a message to the log window. */ int (*confirm_dialog) (char *msg_, ...); /*!< A generic yes/no dialog. * * Returns zero if the cancel button is pressed, one for the ok * button. * * If you specify alternate labels for ..., they are used instead * of the default OK/Cancel ones, and the return value is the * index of the label chosen. * * \warning You MUST pass NULL as the last parameter to this. */ int (*close_confirm_dialog) (); /*!< A close confirmation dialog for unsaved pages, for example, * with options "Close without saving", "Cancel" and "Save". * * Returns zero if the close is cancelled, or one if it should * proceed. * * The HID is responsible for any "Save" action the user may wish * before confirming the close. */ #define HID_CLOSE_CONFIRM_CANCEL 0 #define HID_CLOSE_CONFIRM_OK 1 void (*report_dialog) (char *title_, char *msg_); /*!< Just prints text. */ char *(*prompt_for) (const char *msg_, const char *default_string_); /*!< Prompts the user to enter a string, returns the string. * * If \c default_string isn't NULL, the form is pre-filled with * this value. * * "msg" is like "Enter value:". */ #define HID_FILESELECT_READ 0x01 /*!< Prompts the user for a filename or directory name. * * For GUI HID's this would mean a file select dialog box. * * The 'flags' argument is the bitwise OR of the following values. */ #define HID_FILESELECT_MAY_NOT_EXIST 0x02 /*!< The function calling hid->fileselect will deal with the case * where the selected file already exists. * * If not given, then the gui will prompt with an "overwrite?" * prompt. * * Only used when writing. */ #define HID_FILESELECT_IS_TEMPLATE 0x04 /*!< The call is supposed to return a file template (for gerber * output for example) instead of an actual file. * * Only used when writing. */ char *(*fileselect) (const char *title_, const char *descr_, char *default_file_, char *default_ext_, const char *history_tag_, int flags_); /*!< \c title_ may be used as a dialog box title. Ignored if NULL. * * \c descr_ is a longer help string. Ignored if NULL. * * \c default_file_ is the default file name. Ignored if NULL. * * \c default_ext_ is the default file extension, like ".pdf". * Ignored if NULL. * * \c history_tag_ may be used by the GUI to keep track of file * history. Examples would be "board", "vendor", "renumber", * etc. If NULL, no specific history is kept. * * \c flags_ are the bitwise or of the HID_FILESELECT defines * above. */ int (*attribute_dialog) (HID_Attribute * attrs_, int n_attrs_, HID_Attr_Val * results_, const char * title_, const char * descr_); /*!< A generic dialog to ask for a set of attributes. * * If \c n_attrs_ is zero, \c attrs(.name) must be NULL terminated. * * Returns non-zero if an error occurred (usually, this means the * user cancelled the dialog or something). * * \c title_ is the title of the dialog box. * * \c descr_ (if not NULL) can be a longer description of what the * attributes are used for. * * The HID may choose to ignore it or it may use it for a tooltip * or text in a dialog box, or a help string. */ void (*show_item) (void *item_); /*!< This causes a second window to display, which only shows the * selected item. * * The expose callback is called twice; once to size the extents * of the item, and once to draw it. * * To pass magic values, pass the address of a variable created * for this purpose. */ void (*beep) (void); /*!< Something to alert the user. */ int (*progress) (int so_far_, int total_, const char *message_); /*!< Used by optimizers and autorouter to show progress to the * user. * * Pass all zeros to flush display and remove any dialogs. * * Returns nonzero if the user wishes to cancel the operation. */ HID_DRC_GUI *drc_gui; void (*edit_attributes) (char *owner, AttributeListType *attrlist_); /* Debug drawing support. These APIs must be implemented (non NULL), * but they do not have to be functional. request_debug_draw can * return NULL to indicate debug drawing is not permitted. * * Debug drawing is not guaranteed to be re-entrant. * The caller must not nest requests for debug drawing. */ HID_DRAW *(*request_debug_draw) (void); /*!< Request permission for debug drawing. * * Returns a HID_DRAW pointer which should be used rather than the * global gui->graphics-> for making drawing calls. * * If the return value is NULL, then permission has been denied, * and the drawing must not continue. * * \warning Debug drawing is not guaranteed to be re-entrant. * The caller must not nest requests for debug drawing. */ void (*flush_debug_draw) (void); /*!< Flush pending drawing to the screen. * * May be implemented as a NOOP if the GUI has chosen to send the * debug drawing directly to the screen. */ void (*finish_debug_draw) (void); /*!< When finished, the user must inform the GUI to clean up * resources. * * Any remaining rendering will be flushed to the screen. */ void (*notify_save_pcb) (const char *filename, bool done); /*!< Notification to the GUI around saving the PCB file. * * Called with a false parameter before the save, called again * with true after the save. * * Allows GUIs which watch for file-changes on disk to ignore * our deliberate changes. */ void (*notify_filename_changed) (void); /*!< Notification to the GUI that the PCB file has been renamed. */ }; /*! * \brief Call this as soon as possible from main(). * * No other HID calls are valid until this is called. */ void hid_init (void); /*! * \brief Call this at exit. */ void hid_uninit (void); /*! * \brief When PCB runs in interactive mode, this is called to * instantiate one GUI HID which happens to be the GUI. * * This HID is the one that interacts with the mouse and keyboard. */ HID *hid_find_gui (); /*! * \brief Finds the one printer HID and instantiates it. */ HID *hid_find_printer (void); /*! * \brief Finds the indicated exporter HID and instantiates it. */ HID *hid_find_exporter (const char *); /*! * \brief This returns a NULL-terminated array of available HIDs. * * The only real reason to use this is to locate all the export-style * HIDs. */ HID **hid_enumerate (void); /*! * \brief This function (in the common code) will be called whenever * the GUI needs to redraw the screen, print the board, or export a * layer. * * If item is not NULL, only draw the given item. * Item is only non-NULL if the HID was created via show_item. * * Each time func is called, it should do the following: * * allocate any colors needed, via get_color. * * cycle through the layers, calling set_layer for each layer to be * drawn, and only drawing elements (all or specified) of desired * layers. * * Do *not* assume that the hid that is passed is the GUI hid. * * This callback is also used for printing and exporting. */ void hid_expose_callback (HID * hid_, struct BoxType *region_, void *item_); extern HID *gui; /*!< This is initially set to a "no-gui" gui, and later reset by * main. * * hid_expose_callback also temporarily set it for drawing. */ extern HID *exporter; /*!< This is either NULL or points to the current HID that is being * called to do the exporting. * * The gui HIDs set and unset this var. */ extern HID_Action *current_action; /*!< This is either NULL or points to the current HID_Action that is * being called. * * The action launcher sets and unsets this variable. */ extern int pixel_slop; /*!< The GUI may set this to be approximately the PCB size of a * pixel, to allow for near-misses in selection and changes in * drawing items smaller than a screen pixel. */ #if defined(__cplusplus) && __cplusplus } #endif #endif pcb-4.2.2/src/parse_y.y0000664000076400007640000015106113533277055011657 00000000000000/* * ************************** README ******************* * * If the file format is modified in any way, update * PCB_FILE_VERSION in file.h * * ************************** README ******************* */ %{ /* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * */ /* grammar to parse ASCII input of PCB description */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include "create.h" #include "data.h" #include "error.h" #include "file.h" #include "flags.h" #include "layerflags.h" #include "mymem.h" #include "misc.h" #include "parse_l.h" #include "polygon.h" #include "remove.h" #include "rtree.h" #include "strflags.h" #include "thermal.h" #include "move.h" #ifdef HAVE_LIBDMALLOC # include /* see http://dmalloc.com */ #endif static LayerType *Layer; static PolygonType *Polygon; static SymbolType *Symbol; static int pin_num; static LibraryMenuType *Menu; static bool LayerFlag[MAX_ALL_LAYER]; enum FileType {NOFILE=0, PCBFILE, DATAFILE, FONTFILE} file_type; extern char *yytext; /* defined by LEX */ extern PCBType *yyPCB; extern DataType *yyData; extern ElementType *yyElement; extern FontType *yyFont; extern int yylineno; /* linenumber */ extern char *yyfilename; /* in this file */ static AttributeListType *attr_list; int yyerror(const char *s); int yylex(); static int check_file_version (int); static void do_measure (PLMeasure *m, Coord i, double d, int u); #define M(r,f,d) do_measure (&(r), f, d, 1) /* Macros for interpreting what "measure" means - integer value only, old units (mil), or new units (cmil). */ #define IV(m) integer_value (m) #define OU(m) old_units (m) #define NU(m) new_units (m) static int integer_value (PLMeasure m); static Coord old_units (PLMeasure m); static Coord new_units (PLMeasure m); /* #define YYDEBUG 1 #define YYERROR_VERBOSE 1 int yydebug=1; */ #include "parse_y.h" %} %verbose %union /* define YYSTACK type */ { int integer; double number; char *string; FlagType flagtype; PLMeasure measure; } %token FLOATING /* line thickness, coordinates ... */ %token INTEGER CHAR_CONST /* flags ... */ %token STRING /* element names ... */ %token T_FILEVERSION T_PCB T_LAYER T_VIA T_RAT T_LINE T_ARC T_RECTANGLE T_TEXT T_ELEMENTLINE %token T_ELEMENT T_PIN T_PAD T_GRID T_FLAGS T_SYMBOL T_SYMBOLLINE T_CURSOR %token T_ELEMENTARC T_MARK T_GROUPS T_STYLES T_POLYGON T_POLYGON_HOLE T_NETLIST T_NET T_CONN %token T_AREA T_THERMAL T_DRC T_ATTRIBUTE %token T_UMIL T_CMIL T_MIL T_IN T_NM T_UM T_MM T_M T_KM T_PX %type symbolid %type opt_string %type flags %type number %type measure %% parse : parsepcb | parsedata | parsefont | error { YYABORT; } ; /* %start-doc pcbfile 00pcb @nodetype subsection @nodename %s syntax A special note about units: Older versions of @code{pcb} used mils (1/1000 inch) as the base unit; a value of 500 in the file meant half an inch. Newer versions uses a "high resolution" syntax, where the base unit is 1/100 of a mil (0.000010 inch); a value of 500 in the file means 5 mils. As a general rule, the variants of each entry listed below which use square brackets are the high resolution formats and use the 1/100 mil units, and the ones with parentheses are the older variants and use 1 mil units. Note that when multiple variants are listed, the most recent (and most preferred) format is the first listed. The square bracket syntax specifies only the enclosed values as high resolution. Whenever child elements need high resolution, they have to use square brackets on their own, as in this example: @example Symbol['!' 12] # 12 is a high resolution value ( # <--- this pair is only for grouping and can never be a square SymbolLine[0 4500 0 5000 8] # high resolution SymbolLine(0 10 0 35 8) # standard resolution @end example Symbolic and numeric flags (SFlags and NFlags) are described in @ref{Object Flags}. %end-doc */ /* This parses a full up PCB file */ parsepcb : { /* reset flags for 'used layers'; * init font and data pointers */ int i; file_type = PCBFILE; if (!yyPCB) { Message(_("illegal pcb file format\n")); YYABORT; } for (i = 0; i < MAX_ALL_LAYER; i++) LayerFlag[i] = false; yyFont = &yyPCB->Font; yyData = yyPCB->Data; yyData->pcb = yyPCB; yyData->LayerN = 0; /* Parse the default layer group string, just in case the file doesn't have one */ if (ParseGroupString (Settings.Groups, &yyPCB->LayerGroups, &yyData->LayerN)) { Message(_("illegal default layer-group string\n")); YYABORT; } } pcbfileversion pcbname pcbgrid pcbcursor polyarea pcbthermal pcbdrc pcbflags pcbgroups pcbstyles pcbfont pcbdata pcbnetlist { PCBType *pcb_save = PCB; CreateNewPCBPost (yyPCB, 0); /* initialize the polygon clipping now since * we didn't know the layer grouping before. */ PCB = yyPCB; ALLPOLYGON_LOOP (yyData); { InitClip (yyData, layer, polygon); } ENDALL_LOOP; PCB = pcb_save; } ; /* This is a file that has pcb data but none of the header stuff */ parsedata : { /* reset flags for 'used layers'; * init font and data pointers */ int i; file_type = DATAFILE; /* Loading a footprint file as a layout */ if (yyPCB) { yyFont = &yyPCB->Font; yyData = yyPCB->Data; yyData->pcb = yyPCB; } /* e.g. loading data to a buffer */ else if (!yyData || !yyFont) { Message(_("PCB data not initialized! Cannot load data file\n")); YYABORT; } for (i = 0; i < MAX_ALL_LAYER; i++) LayerFlag[i] = false; yyData->LayerN = 0; } pcbdata ; pcbfont : { file_type = FONTFILE; } parsefont | ; parsefont : { /* mark all symbols invalid */ int i; if (!yyFont) { Message(_("illegal file format\n")); YYABORT; } yyFont->Valid = false; for (i = 0; i <= MAX_FONTPOSITION; i++) free (yyFont->Symbol[i].Line); bzero(yyFont->Symbol, sizeof(yyFont->Symbol)); } symbols { yyFont->Valid = true; SetFontInfo(yyFont); } ; /* %start-doc pcbfile FileVersion @syntax FileVersion[Version] @end syntax @table @var @item Version File format version. This version number represents the date when the pcb file format was last changed. @end table Any version of pcb build from sources equal to or newer than this number should be able to read the file. If this line is not present in the input file then file format compatibility is not checked. %end-doc */ pcbfileversion : | T_FILEVERSION '[' INTEGER ']' { if (check_file_version ($3) != 0) { YYABORT; } } ; /* %start-doc pcbfile PCB @noindent Current syntax: @syntax PCB ["Name" Width Height] @end syntax @noindent Legacy syntax: @syntax PCB ("Name" Width Height) PCB ("Name") @end syntax @table @var @item Name Name of the PCB project @item Width Height Size of the board @end table If you don't specify the size of the board, a very large default is chosen. %end-doc */ pcbname : T_PCB '(' STRING ')' { yyPCB->Name = $3; yyPCB->MaxWidth = MAX_COORD; yyPCB->MaxHeight = MAX_COORD; } | T_PCB '(' STRING measure measure ')' { yyPCB->Name = $3; yyPCB->MaxWidth = OU ($4); yyPCB->MaxHeight = OU ($5); } | T_PCB '[' STRING measure measure ']' { yyPCB->Name = $3; yyPCB->MaxWidth = NU ($4); yyPCB->MaxHeight = NU ($5); } ; /* %start-doc pcbfile Grid @noindent Current syntax: @syntax Grid [Step OffsetX OffsetY Visible] @end syntax @noindent Legacy syntax: @syntax Grid (Step OffsetX OffsetY Visible) Grid (Step OffsetX OffsetY) @end syntax @table @var @item Step Distance from one grid point to adjacent points. This value may be a floating point number for the first two variants. @item OffsetX OffsetY The "origin" of the grid. Normally zero. @item Visible If non-zero, the grid will be visible on the screen. @end table %end-doc */ pcbgrid : pcbgridold | pcbgridnew | pcbhigrid ; pcbgridold : T_GRID '(' measure measure measure ')' { yyPCB->Grid = OU ($3); yyPCB->GridOffsetX = OU ($4); yyPCB->GridOffsetY = OU ($5); } ; pcbgridnew : T_GRID '(' measure measure measure INTEGER ')' { yyPCB->Grid = OU ($3); yyPCB->GridOffsetX = OU ($4); yyPCB->GridOffsetY = OU ($5); if ($6) Settings.DrawGrid = true; else Settings.DrawGrid = false; } ; pcbhigrid : T_GRID '[' measure measure measure INTEGER ']' { yyPCB->Grid = NU ($3); yyPCB->GridOffsetX = NU ($4); yyPCB->GridOffsetY = NU ($5); if ($6) Settings.DrawGrid = true; else Settings.DrawGrid = false; } ; /* %start-doc pcbfile Cursor @noindent Legacy syntax: @syntax Cursor [X Y Zoom] Cursor (X Y Zoom) @end syntax @table @var @item X Y Location of the cursor when the board was saved. As of November 2012 the cursor position is not written to file anymore. Older versions of pcb ignore the absence of this line in the pcb file. @item Zoom The current zoom factor. Note that a zoom factor of "0" means 1 mil per screen pixel, N means @math{2^N} mils per screen pixel, etc. The first variant accepts floating point numbers. The special value "1000" means "zoom to fit" This field is ignored by PCB. @end table %end-doc */ pcbcursor : T_CURSOR '(' measure measure number ')' { yyPCB->CursorX = OU ($3); yyPCB->CursorY = OU ($4); } | T_CURSOR '[' measure measure number ']' { yyPCB->CursorX = NU ($3); yyPCB->CursorY = NU ($4); } | ; /* %start-doc pcbfile PolyArea @syntax PolyArea [Area] @end syntax @table @var @item Area Minimum area of polygon island to retain. If a polygon has clearances that cause an isolated island to be created, then will only be retained if the area exceeds this minimum area. @end table %end-doc */ polyarea : | T_AREA '[' number ']' { /* Read in cmil^2 for now; in future this should be a noop. */ yyPCB->IsleArea = MIL_TO_COORD (MIL_TO_COORD ($3) / 100.0) / 100.0; } ; /* %start-doc pcbfile Thermal @syntax Thermal [Scale] @end syntax @table @var @item Scale Relative size of thermal fingers. A value of 1.0 makes the finger width twice the clearance gap width (measured across the gap, not diameter). The normal value is 0.5, which results in a finger width the same as the clearance gap width. @end table %end-doc */ pcbthermal : | T_THERMAL '[' number ']' { yyPCB->ThermScale = $3; } ; /* %start-doc pcbfile DRC @syntax DRC [Bloat Shrink Line Silk Drill Ring] DRC [Bloat Shrink Line Silk] DRC [Bloat Shrink Line] @end syntax @table @var @item Bloat Minimum spacing between copper. @item Shrink Minimum copper overlap to guarantee connectivity. @item Line Minimum line thickness. @item Silk Minimum silk thickness. @item Drill Minimum drill size. @item Ring Minimum width of the annular ring around pins and vias. @end table %end-doc */ pcbdrc : | pcbdrc1 | pcbdrc2 | pcbdrc3 ; pcbdrc1 : T_DRC '[' measure measure measure ']' { yyPCB->Bloat = NU ($3); yyPCB->Shrink = NU ($4); yyPCB->minWid = NU ($5); yyPCB->minRing = NU ($5); } ; pcbdrc2 : T_DRC '[' measure measure measure measure ']' { yyPCB->Bloat = NU ($3); yyPCB->Shrink = NU ($4); yyPCB->minWid = NU ($5); yyPCB->minSlk = NU ($6); yyPCB->minRing = NU ($5); } ; pcbdrc3 : T_DRC '[' measure measure measure measure measure measure ']' { yyPCB->Bloat = NU ($3); yyPCB->Shrink = NU ($4); yyPCB->minWid = NU ($5); yyPCB->minSlk = NU ($6); yyPCB->minDrill = NU ($7); yyPCB->minRing = NU ($8); } ; /* %start-doc pcbfile Flags @syntax Flags(Number) @end syntax @table @var @item Number A number, whose value is normally given in hex, individual bits of which represent pcb-wide flags as defined in @ref{PCBFlags}. @end table %end-doc */ pcbflags : T_FLAGS '(' INTEGER ')' { yyPCB->Flags = MakeFlags ($3 & PCB_FLAGS); } | T_FLAGS '(' STRING ')' { yyPCB->Flags = string_to_pcbflags ($3, yyerror); free ($3); } | ; /* %start-doc pcbfile Groups @syntax Groups("String") @end syntax @table @var @item String Encodes the layer grouping information. Each group is separated by a colon, each member of each group is separated by a comma. Group members are either numbers from @code{1}..@var{N} for each layer, and the letters @code{c} or @code{s} representing the component side and solder side of the board. Including @code{c} or @code{s} marks that group as being the top or bottom side of the board. @example Groups("1,2,c:3:4:5,6,s:7,8") @end example @end table %end-doc */ pcbgroups : T_GROUPS '(' STRING ')' { if (ParseGroupString ($3, &yyPCB->LayerGroups, &yyData->LayerN)) { Message(_("illegal layer-group string\n")); YYABORT; } free ($3); } | ; /* %start-doc pcbfile Styles @syntax Styles("String") @end syntax @table @var @item String Encodes the four routing styles @code{pcb} knows about. The four styles are separated by colons. Each style consists of five parameters as follows: @table @var @item Name The name of the style. @item Thickness Width of lines and arcs. @item Diameter Copper diameter of pins and vias. @item Drill Drill diameter of pins and vias. @item Keepaway Minimum spacing to other nets. If omitted, 10 mils is the default. @item Via Mask Aperture (optional) The diameter of the solder mask opening around vias. A value of 0 produces a tented via. This parameter is omitted if 0 for backwards compatibility. @end table @end table @noindent Current syntax example: @example Styles["Logic,1000,3600,2000,1000,0:Power,2500,6000,3500,1000,70mil: @ @ @ Line,4000,6000,3500,1000:Breakout,600,2402,1181,600"] @end example @noindent Legacy syntax example: @example Styles("Signal,10,40,20:Power,25,60,35:Fat,40,60,35:Skinny,8,36,20") @end example @noindent Note that strings in actual files cannot span lines; the above example is split across lines only to make it readable. %end-doc */ pcbstyles : T_STYLES '(' STRING ')' { if (ParseRouteString(($3 == NULL ? "" : $3), &yyPCB->RouteStyle[0], "mil")) { Message(_("illegal route-style string\n")); YYABORT; } free ($3); } | T_STYLES '[' STRING ']' { if (ParseRouteString(($3 == NULL ? "" : $3), &yyPCB->RouteStyle[0], "cmil")) { Message(_("illegal route-style string\n")); YYABORT; } free ($3); } | ; pcbdata : pcbdefinitions | ; pcbdefinitions : pcbdefinition | pcbdefinitions pcbdefinition ; pcbdefinition : via | { attr_list = & yyPCB->Attributes; } attribute | rats | layer | { if ( file_type == DATAFILE ) { if (yyPCB != NULL) { /* This case is when we load a footprint with file->open, or from the command line */ yyFont = &yyPCB->Font; yyData = yyPCB->Data; yyData->pcb = yyPCB; yyData->LayerN = 0; } } } element { if (file_type == DATAFILE){ PCBType *pcb_save = PCB; ElementType *e; if (yyPCB != NULL) { /* This case is when we load a footprint with file->open, or from the command line */ CreateNewPCBPost (yyPCB, 0); ParseGroupString("1,c:2,s", &yyPCB->LayerGroups, &yyData->LayerN); e = yyPCB->Data->Element->data; /* we know there's only one */ PCB = yyPCB; MoveElementLowLevel (yyPCB->Data, e, -e->BoundingBox.X1, -e->BoundingBox.Y1); PCB = pcb_save; yyPCB->MaxWidth = e->BoundingBox.X2; yyPCB->MaxHeight = e->BoundingBox.Y2; yyPCB->is_footprint = 1; } } } /* | element*/ ; via : via_ehi_format | via_hi_format | via_2.0_format | via_1.7_format | via_newformat | via_oldformat ; /* %start-doc pcbfile Via @noindent Current syntax: @syntax Via [X Y Thickness Clearance Mask Drill BuriedFrom BuriedTo "Name" SFlags] Via [X Y Thickness Clearance Mask Drill "Name" SFlags] @end syntax @noindent Legacy syntax: @syntax Via (X Y Thickness Clearance Mask Drill "Name" NFlags) Via (X Y Thickness Clearance Drill "Name" NFlags) Via (X Y Thickness Drill "Name" NFlags) Via (X Y Thickness "Name" NFlags) @end syntax @table @var @item X Y coordinates of center @item Thickness outer diameter of copper annulus @item Clearance add to thickness to get clearance diameter @item Mask diameter of solder mask opening @item Drill diameter of drill @item BuriedFrom upper layer from which the buried via starts @item BuriedTo lower layer to which the buried via ends @item Name string, name of via (vias have names?) @item SFlags symbolic or numerical flags @item NFlags numerical flags only @end table Example: @example Via[15.0000mm 11.0000mm 24.00mil 12.00mil 0.0000 11.81mil 0 5 "" ""] @end example The above example gives a via at coordinates x=15.0000 mm, y=11.0000mm, with a 24.00mil thickness, a 6.00mil clearance, a 0.0000 gap, a -12.00mil mask (tented), a 11.81mil drill width, starting at the top layer ("0"), ending at the 3rd copper layer ("2"), and has no names and no flags. %end-doc */ via_ehi_format /* x, y, thickness, clearance, mask, drilling-hole, buried_from, buried_to, name, flags */ : T_VIA '[' measure measure measure measure measure measure INTEGER INTEGER STRING flags ']' { CreateNewViaEx (yyData, NU ($3), NU ($4), NU ($5), NU ($6), NU ($7), NU ($8), $11, $12, $9, $10); free ($11); } ; via_hi_format /* x, y, thickness, clearance, mask, drilling-hole, name, flags */ : T_VIA '[' measure measure measure measure measure measure STRING flags ']' { CreateNewVia(yyData, NU ($3), NU ($4), NU ($5), NU ($6), NU ($7), NU ($8), $9, $10); free ($9); } ; via_2.0_format /* x, y, thickness, clearance, mask, drilling-hole, name, flags */ : T_VIA '(' measure measure measure measure measure measure STRING INTEGER ')' { CreateNewVia(yyData, OU ($3), OU ($4), OU ($5), OU ($6), OU ($7), OU ($8), $9, OldFlags($10)); free ($9); } ; via_1.7_format /* x, y, thickness, clearance, drilling-hole, name, flags */ : T_VIA '(' measure measure measure measure measure STRING INTEGER ')' { CreateNewVia(yyData, OU ($3), OU ($4), OU ($5), OU ($6), OU ($5) + OU($6), OU ($7), $8, OldFlags($9)); free ($8); } ; via_newformat /* x, y, thickness, drilling-hole, name, flags */ : T_VIA '(' measure measure measure measure STRING INTEGER ')' { CreateNewVia(yyData, OU ($3), OU ($4), OU ($5), 2*GROUNDPLANEFRAME, OU($5) + 2*MASKFRAME, OU ($6), $7, OldFlags($8)); free ($7); } ; via_oldformat /* old format: x, y, thickness, name, flags */ : T_VIA '(' measure measure measure STRING INTEGER ')' { Coord hole = (OU($5) * DEFAULT_DRILLINGHOLE); CreateNewVia(yyData, OU ($3), OU ($4), OU ($5), 2*GROUNDPLANEFRAME, OU($5) + 2*MASKFRAME, hole, $6, OldFlags($7)); free ($6); } ; /* %start-doc pcbfile Rat @noindent Current syntax: @syntax Rat [X1 Y1 Group1 X2 Y2 Group2 SFlags] @end syntax @noindent Legacy Syntax: @syntax Rat (X1 Y1 Group1 X2 Y2 Group2 NFlags) @end syntax @table @var @item X1 Y1 X2 Y2 The endpoints of the rat line. @item Group1 Group2 The layer group each end is connected on. @item SFlags Symbolic or numeric flags. @item NFlags Numeric flags. @end table %end-doc */ rats : T_RAT '[' measure measure INTEGER measure measure INTEGER flags ']' { CreateNewRat(yyData, NU ($3), NU ($4), NU ($6), NU ($7), $5, $8, Settings.RatThickness, $9); } | T_RAT '(' measure measure INTEGER measure measure INTEGER INTEGER ')' { CreateNewRat(yyData, OU ($3), OU ($4), OU ($6), OU ($7), $5, $8, Settings.RatThickness, OldFlags($9)); } ; /* %start-doc pcbfile Layer @syntax Layer (LayerNum "Name" "Flags") ( @ @ @ @dots{} contents @dots{} ) @end syntax @table @var @item LayerNum The layer number. Layers are numbered sequentially, starting with 1. The last two layers (9 and 10 by default) are solder-side silk and component-side silk, in that order. The two silk layers also mark top and bottom side; the layer group where the solder-side silk layer is member in is the solder side group. Analogous for the other side. @item Name The layer name. For layout files predating layer flags the name also defines the layer type in some situations. For example, a layer named @emph{outline} was considered to be the layer defining the extents of the board. @item Flags Layer flags. Currently this is the layer type, like @emph{copper}, @emph{silk} or @emph{outline}. For a complete list see layertype_name[] in layerflags.c. With layer flags missing, the type of layer is guessed at load time, mostly by the layer name. This mechanism ensures compatibility with older layouts. @item contents The contents of the layer, which may include attributes, lines, arcs, rectangles, text, and polygons. @end table %end-doc */ layer /* name */ : T_LAYER '(' INTEGER STRING opt_string ')' '(' { if ($3 <= 0 || $3 > MAX_ALL_LAYER) { yyerror("Layernumber out of range"); YYABORT; } if (LayerFlag[$3-1]) { yyerror("Layernumber used twice"); YYABORT; } Layer = &yyData->Layer[$3-1]; /* memory for name is already allocated */ Layer->Name = $4; if (Layer->Name == NULL) Layer->Name = strdup(""); LayerFlag[$3-1] = true; if ($5) Layer->Type = string_to_layertype ($5, yyerror); else Layer->Type = guess_layertype ($4, $3, yyData); if ($5 != NULL) free ($5); } layerdata ')' ; layerdata : layerdefinitions | ; layerdefinitions : layerdefinition | layerdefinitions layerdefinition ; layerdefinition : line_hi_format | line_1.7_format | line_oldformat | arc_hi_format | arc_1.7_format | arc_oldformat /* x1, y1, x2, y2, flags */ | T_RECTANGLE '(' measure measure measure measure INTEGER ')' { CreateNewPolygonFromRectangle(Layer, OU ($3), OU ($4), OU ($3) + OU ($5), OU ($4) + OU ($6), OldFlags($7)); } | text_hi_format | text_newformat | text_oldformat | { attr_list = & Layer->Attributes; } attribute | polygon_format /* %start-doc pcbfile Line @noindent Current syntax: @syntax Line [X1 Y1 X2 Y2 Thickness Clearance SFlags] @end syntax @noindent Legacy syntax: @syntax Line (X1 Y1 X2 Y2 Thickness Clearance NFlags) Line (X1 Y1 X2 Y2 Thickness NFlags) @end syntax @table @var @item X1 Y1 X2 Y2 The end points of the line @item Thickness The width of the line @item Clearance The amount of space cleared around the line when the line passes through a polygon. The clearance is added to the thickness to get the thickness of the clear; thus the space between the line and the polygon is @math{Clearance/2} wide. @item SFlags Symbolic or numeric flags @item NFlags Numeric flags. @end table %end-doc */ line_hi_format /* x1, y1, x2, y2, thickness, clearance, flags */ : T_LINE '[' measure measure measure measure measure measure flags ']' { CreateNewLineOnLayer(Layer, NU ($3), NU ($4), NU ($5), NU ($6), NU ($7), NU ($8), $9); } ; line_1.7_format /* x1, y1, x2, y2, thickness, clearance, flags */ : T_LINE '(' measure measure measure measure measure measure INTEGER ')' { CreateNewLineOnLayer(Layer, OU ($3), OU ($4), OU ($5), OU ($6), OU ($7), OU ($8), OldFlags($9)); } ; line_oldformat /* x1, y1, x2, y2, thickness, flags */ : T_LINE '(' measure measure measure measure measure measure ')' { /* eliminate old-style rat-lines */ if ((IV ($8) & RATFLAG) == 0) CreateNewLineOnLayer(Layer, OU ($3), OU ($4), OU ($5), OU ($6), OU ($7), 200*GROUNDPLANEFRAME, OldFlags(IV ($8))); } ; /* %start-doc pcbfile Arc @noindent Current syntax: @syntax Arc [X Y RadiusX RadiusY Thickness Clearance StartAngle DeltaAngle SFlags] @end syntax @noindent Legacy syntax: @syntax Arc (X Y RadiusX RadiusY Thickness Clearance StartAngle DeltaAngle NFlags) Arc (X Y RadiusX RadiusY Thickness StartAngle DeltaAngle NFlags) @end syntax @table @var @item X Y Coordinates of the center of the arc. @item RadiusX RadiusY The RadiusX and RadiusY, from the center to the edge (centerline of the trace). The bounds of the circle of which this arc is a segment, is thus @math{2*RadiusX} by @math{2*RadiusY}. @item Thickness The width of the copper trace which forms the arc. @item Clearance The amount of space cleared around the arc when the line passes through a polygon. The clearance is added to the thickness to get the thickness of the clear; thus the space between the arc and the polygon is @math{Clearance/2} wide. @item StartAngle The angle of one end of the arc, in degrees. In PCB, an angle of zero points left (negative X direction), and 90 degrees points down (positive Y direction). @item DeltaAngle The sweep of the arc. This may be negative. Positive angles sweep counterclockwise. @item SFlags Symbolic or numeric flags. @item NFlags Numeric flags. @end table %end-doc */ arc_hi_format /* x, y, width, height, thickness, clearance, startangle, delta, flags */ : T_ARC '[' measure measure measure measure measure measure number number flags ']' { CreateNewArcOnLayer(Layer, NU ($3), NU ($4), NU ($5), NU ($6), $9, $10, NU ($7), NU ($8), $11); } ; arc_1.7_format /* x, y, width, height, thickness, clearance, startangle, delta, flags */ : T_ARC '(' measure measure measure measure measure measure number number INTEGER ')' { CreateNewArcOnLayer(Layer, OU ($3), OU ($4), OU ($5), OU ($6), $9, $10, OU ($7), OU ($8), OldFlags($11)); } ; arc_oldformat /* x, y, width, height, thickness, startangle, delta, flags */ : T_ARC '(' measure measure measure measure measure measure number INTEGER ')' { CreateNewArcOnLayer(Layer, OU ($3), OU ($4), OU ($5), OU ($5), IV ($8), $9, OU ($7), 200*GROUNDPLANEFRAME, OldFlags($10)); } ; /* %start-doc pcbfile Text @noindent Current syntax: @syntax Text [X Y Direction Scale "String" SFlags] @end syntax @noindent Legacy syntax: @syntax Text (X Y Direction Scale "String" NFlags) Text (X Y Direction "String" NFlags) @end syntax @table @var @item X Y The location of the upper left corner of the text. @item Direction 0 means text is drawn left to right, 1 means up, 2 means right to left (i.e. upside down), and 3 means down. @item Scale Size of the text, as a percentage of the ``default'' size of of the font (the default font is about 40 mils high). Default is 100 (40 mils). @item String The string to draw. @item SFlags Symbolic or numeric flags. @item NFlags Numeric flags. @end table %end-doc */ text_oldformat /* x, y, direction, text, flags */ : T_TEXT '(' measure measure number STRING INTEGER ')' { /* use a default scale of 100% */ CreateNewText(Layer,yyFont,OU ($3), OU ($4), $5, 100, $6, OldFlags($7)); free ($6); } ; text_newformat /* x, y, direction, scale, text, flags */ : T_TEXT '(' measure measure number number STRING INTEGER ')' { if ($8 & ONSILKFLAG) { LayerType *lay = &yyData->Layer[yyData->LayerN + (($8 & ONSOLDERFLAG) ? BOTTOM_SILK_LAYER : TOP_SILK_LAYER)]; CreateNewText(lay ,yyFont, OU ($3), OU ($4), $5, $6, $7, OldFlags($8)); } else CreateNewText(Layer, yyFont, OU ($3), OU ($4), $5, $6, $7, OldFlags($8)); free ($7); } ; text_hi_format /* x, y, direction, scale, text, flags */ : T_TEXT '[' measure measure number number STRING flags ']' { /* FIXME: shouldn't know about .f */ /* I don't think this matters because anything with hi_format * will have the silk on its own layer in the file rather * than using the ONSILKFLAG and having it in a copper layer. * Thus there is no need for anything besides the 'else' * part of this code. */ if ($8.f & ONSILKFLAG) { LayerType *lay = &yyData->Layer[yyData->LayerN + (($8.f & ONSOLDERFLAG) ? BOTTOM_SILK_LAYER : TOP_SILK_LAYER)]; CreateNewText(lay, yyFont, NU ($3), NU ($4), $5, $6, $7, $8); } else CreateNewText(Layer, yyFont, NU ($3), NU ($4), $5, $6, $7, $8); free ($7); } ; /* %start-doc pcbfile Polygon @noindent Current syntax: @syntax Polygon (SFlags) ( @ @ @ @dots{} [X Y] @dots{} @ @ @ Hole ( @ @ @ @ @ @ @dots{} [X Y] @dots{} @ @ @ ) @ @ @ @dots{} ) @end syntax @noindent Legacy syntax: @syntax Polygon (SFlags) ( @ @ @ @dots{} (X Y) @dots{} @ @ @ Hole ( @ @ @ @ @ @ @dots{} (X Y) @dots{} @ @ @ ) @ @ @ @dots{} ) @end syntax @table @var @item SFlags Symbolic or numeric flags. @item X Y Coordinates of each vertex. You must list at least three coordinates. @item Hole (...) Defines a hole within the polygon's outer contour. There may be zero or more such sections. @end table %end-doc */ polygon_format : /* flags are passed in */ T_POLYGON '(' flags ')' '(' { Polygon = CreateNewPolygon(Layer, $3); } polygonpoints polygonholes ')' { Cardinal contour, contour_start, contour_end; bool bad_contour_found = false; /* ignore junk */ for (contour = 0; contour <= Polygon->HoleIndexN; contour++) { contour_start = (contour == 0) ? 0 : Polygon->HoleIndex[contour - 1]; contour_end = (contour == Polygon->HoleIndexN) ? Polygon->PointN : Polygon->HoleIndex[contour]; if (contour_end - contour_start < 3) bad_contour_found = true; } if (bad_contour_found) { Message(_("WARNING parsing file '%s'\n" " line: %i\n" " description: 'ignored polygon " "(< 3 points in a contour)'\n"), yyfilename, yylineno); DestroyObject(yyData, POLYGON_TYPE, Layer, Polygon, Polygon); } else { SetPolygonBoundingBox (Polygon); if (!Layer->polygon_tree) Layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0); } } ; polygonholes : /* empty */ | polygonholes polygonhole ; polygonhole : T_POLYGON_HOLE '(' { CreateNewHoleInPolygon (Polygon); } polygonpoints ')' ; polygonpoints : /* empty */ | polygonpoint polygonpoints ; polygonpoint /* xcoord ycoord */ : '(' measure measure ')' { CreateNewPointInPolygon(Polygon, OU ($2), OU ($3)); } | '[' measure measure ']' { CreateNewPointInPolygon(Polygon, NU ($2), NU ($3)); } ; /* %start-doc pcbfile Element @noindent Current syntax: @syntax Element [SFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TSFlags] ( @ @ @ @dots{} contents @dots{} ) @end syntax @noindent Legacy syntax: @syntax Element (NFlags "Desc" "Name" "Value" MX MY TX TY TDir TScale TNFlags) ( Element (NFlags "Desc" "Name" "Value" TX TY TDir TScale TNFlags) ( Element (NFlags "Desc" "Name" TX TY TDir TScale TNFlags) ( Element ("Desc" "Name" TX TY TDir TScale TNFlags) ( @ @ @ @dots{} contents @dots{} ) @end syntax @table @var @item SFlags Symbolic or numeric flags, for the element as a whole. @item NFlags Numeric flags, for the element as a whole. @item Desc The description of the element. This is one of the three strings which can be displayed on the screen. @item Name The name of the element, usually the reference designator. @item Value The value of the element. @item MX MY The location of the element's mark. This is the reference point for placing the element and its pins and pads. @item TX TY The upper left corner of the text (one of the three strings). @item TDir The relative direction of the text. 0 means left to right for an unrotated element, 1 means up, 2 left, 3 down. @item TScale Size of the text, as a percentage of the ``default'' size of of the font (the default font is about 40 mils high). Default is 100 (40 mils). @item TSFlags Symbolic or numeric flags, for the text. @item TNFlags Numeric flags, for the text. @end table Elements may contain pins, pads, element lines, element arcs, attributes, and (for older elements) an optional mark. Note that element definitions that have the mark coordinates in the element line, only support pins and pads which use relative coordinates. The pin and pad coordinates are relative to the mark. Element definitions which do not include the mark coordinates in the element line, may have a Mark definition in their contents, and only use pin and pad definitions which use absolute coordinates. %end-doc */ element : element_oldformat | element_1.3.4_format | element_newformat | element_1.7_format | element_hi_format ; element_oldformat /* element_flags, description, pcb-name, * text_x, text_y, text_direction, text_scale, text_flags */ : T_ELEMENT '(' STRING STRING measure measure INTEGER ')' '(' { yyElement = CreateNewElement(yyData, yyFont, NoFlags(), $3, $4, NULL, OU ($5), OU ($6), $7, 100, NoFlags(), false); free ($3); free ($4); pin_num = 1; } elementdefinitions ')' { SetElementBoundingBox(yyData, yyElement, yyFont); } ; element_1.3.4_format /* element_flags, description, pcb-name, * text_x, text_y, text_direction, text_scale, text_flags */ : T_ELEMENT '(' INTEGER STRING STRING measure measure measure measure INTEGER ')' '(' { yyElement = CreateNewElement(yyData, yyFont, OldFlags($3), $4, $5, NULL, OU ($6), OU ($7), IV ($8), IV ($9), OldFlags($10), false); free ($4); free ($5); pin_num = 1; } elementdefinitions ')' { SetElementBoundingBox(yyData, yyElement, yyFont); } ; element_newformat /* element_flags, description, pcb-name, value, * text_x, text_y, text_direction, text_scale, text_flags */ : T_ELEMENT '(' INTEGER STRING STRING STRING measure measure measure measure INTEGER ')' '(' { yyElement = CreateNewElement(yyData, yyFont, OldFlags($3), $4, $5, $6, OU ($7), OU ($8), IV ($9), IV ($10), OldFlags($11), false); free ($4); free ($5); free ($6); pin_num = 1; } elementdefinitions ')' { SetElementBoundingBox(yyData, yyElement, yyFont); } ; element_1.7_format /* element_flags, description, pcb-name, value, mark_x, mark_y, * text_x, text_y, text_direction, text_scale, text_flags */ : T_ELEMENT '(' INTEGER STRING STRING STRING measure measure measure measure number number INTEGER ')' '(' { yyElement = CreateNewElement(yyData, yyFont, OldFlags($3), $4, $5, $6, OU ($7) + OU ($9), OU ($8) + OU ($10), $11, $12, OldFlags($13), false); yyElement->MarkX = OU ($7); yyElement->MarkY = OU ($8); free ($4); free ($5); free ($6); } relementdefs ')' { SetElementBoundingBox(yyData, yyElement, yyFont); } ; element_hi_format /* element_flags, description, pcb-name, value, mark_x, mark_y, * text_x, text_y, text_direction, text_scale, text_flags */ : T_ELEMENT '[' flags STRING STRING STRING measure measure measure measure number number flags ']' '(' { yyElement = CreateNewElement(yyData, yyFont, $3, $4, $5, $6, NU ($7) + NU ($9), NU ($8) + NU ($10), $11, $12, $13, false); yyElement->MarkX = NU ($7); yyElement->MarkY = NU ($8); free ($4); free ($5); free ($6); } relementdefs ')' { SetElementBoundingBox(yyData, yyElement, yyFont); } ; /* %start-doc pcbfile ElementLine @noindent Current syntax: @syntax ElementLine [X1 Y1 X2 Y2 Thickness] @end syntax @noindent Legacy syntax: @syntax ElementLine (X1 Y1 X2 Y2 Thickness) @end syntax @table @var @item X1 Y1 X2 Y2 Coordinates of the endpoints of the line. These are relative to the Element's mark point for new element formats, or absolute for older formats. @item Thickness The width of the silk for this line. @end table %end-doc */ /* %start-doc pcbfile ElementArc @noindent Current syntax: @syntax ElementArc [X Y Width Height StartAngle DeltaAngle Thickness] @end syntax @noindent Legacy syntax: @syntax ElementArc (X Y Width Height StartAngle DeltaAngle Thickness) @end syntax @table @var @item X Y Coordinates of the center of the arc. These are relative to the Element's mark point for new element formats, or absolute for older formats. @item Width Height The width and height, from the center to the edge. The bounds of the circle of which this arc is a segment, is thus @math{2*Width} by @math{2*Height}. @item StartAngle The angle of one end of the arc, in degrees. In PCB, an angle of zero points left (negative X direction), and 90 degrees points down (positive Y direction). @item DeltaAngle The sweep of the arc. This may be negative. Positive angles sweep counterclockwise. @item Thickness The width of the silk line which forms the arc. @end table %end-doc */ /* %start-doc pcbfile Mark @noindent Legacy syntax: @syntax Mark [X Y] Mark (X Y) @end syntax @table @var @item X Y Coordinates of the Mark, for older element formats that don't have the mark as part of the Element line. @end table %end-doc */ elementdefinitions : elementdefinition | elementdefinitions elementdefinition ; elementdefinition : pin_1.6.3_format | pin_newformat | pin_oldformat | pad_newformat | pad /* x1, y1, x2, y2, thickness */ | T_ELEMENTLINE '[' measure measure measure measure measure ']' { CreateNewLineInElement(yyElement, NU ($3), NU ($4), NU ($5), NU ($6), NU ($7)); } /* x1, y1, x2, y2, thickness */ | T_ELEMENTLINE '(' measure measure measure measure measure ')' { CreateNewLineInElement(yyElement, OU ($3), OU ($4), OU ($5), OU ($6), OU ($7)); } /* x, y, width, height, startangle, anglediff, thickness */ | T_ELEMENTARC '[' measure measure measure measure number number measure ']' { CreateNewArcInElement(yyElement, NU ($3), NU ($4), NU ($5), NU ($6), $7, $8, NU ($9)); } /* x, y, width, height, startangle, anglediff, thickness */ | T_ELEMENTARC '(' measure measure measure measure number number measure ')' { CreateNewArcInElement(yyElement, OU ($3), OU ($4), OU ($5), OU ($6), $7, $8, OU ($9)); } /* x, y position */ | T_MARK '[' measure measure ']' { yyElement->MarkX = NU ($3); yyElement->MarkY = NU ($4); } | T_MARK '(' measure measure ')' { yyElement->MarkX = OU ($3); yyElement->MarkY = OU ($4); } | { attr_list = & yyElement->Attributes; } attribute ; relementdefs : relementdef | relementdefs relementdef ; relementdef : pin_1.7_format | pin_hi_format | pad_1.7_format | pad_hi_format /* x1, y1, x2, y2, thickness */ | T_ELEMENTLINE '[' measure measure measure measure measure ']' { CreateNewLineInElement(yyElement, NU ($3) + yyElement->MarkX, NU ($4) + yyElement->MarkY, NU ($5) + yyElement->MarkX, NU ($6) + yyElement->MarkY, NU ($7)); } | T_ELEMENTLINE '(' measure measure measure measure measure ')' { CreateNewLineInElement(yyElement, OU ($3) + yyElement->MarkX, OU ($4) + yyElement->MarkY, OU ($5) + yyElement->MarkX, OU ($6) + yyElement->MarkY, OU ($7)); } /* x, y, width, height, startangle, anglediff, thickness */ | T_ELEMENTARC '[' measure measure measure measure number number measure ']' { CreateNewArcInElement(yyElement, NU ($3) + yyElement->MarkX, NU ($4) + yyElement->MarkY, NU ($5), NU ($6), $7, $8, NU ($9)); } | T_ELEMENTARC '(' measure measure measure measure number number measure ')' { CreateNewArcInElement(yyElement, OU ($3) + yyElement->MarkX, OU ($4) + yyElement->MarkY, OU ($5), OU ($6), $7, $8, OU ($9)); } | { attr_list = & yyElement->Attributes; } attribute ; /* %start-doc pcbfile Pin @noindent Current syntax: @syntax Pin [rX rY Thickness Clearance Mask Drill "Name" "Number" SFlags] @end syntax @noindent Legacy syntax: @syntax Pin (rX rY Thickness Clearance Mask Drill "Name" "Number" NFlags) Pin (aX aY Thickness Drill "Name" "Number" NFlags) Pin (aX aY Thickness Drill "Name" NFlags) Pin (aX aY Thickness "Name" NFlags) @end syntax @table @var @item rX rY coordinates of center, relative to the element's mark @item aX aY absolute coordinates of center. @item Thickness outer diameter of copper annulus @item Clearance add to thickness to get clearance diameter @item Mask diameter of solder mask opening @item Drill diameter of drill @item Name name of pin @item Number number of pin @item SFlags symbolic or numerical flags @item NFlags numerical flags only @end table %end-doc */ pin_hi_format /* x, y, thickness, clearance, mask, drilling hole, name, number, flags */ : T_PIN '[' measure measure measure measure measure measure STRING STRING flags ']' { CreateNewPin(yyElement, NU ($3) + yyElement->MarkX, NU ($4) + yyElement->MarkY, NU ($5), NU ($6), NU ($7), NU ($8), $9, $10, $11); free ($9); free ($10); } ; pin_1.7_format /* x, y, thickness, clearance, mask, drilling hole, name, number, flags */ : T_PIN '(' measure measure measure measure measure measure STRING STRING INTEGER ')' { CreateNewPin(yyElement, OU ($3) + yyElement->MarkX, OU ($4) + yyElement->MarkY, OU ($5), OU ($6), OU ($7), OU ($8), $9, $10, OldFlags($11)); free ($9); free ($10); } ; pin_1.6.3_format /* x, y, thickness, drilling hole, name, number, flags */ : T_PIN '(' measure measure measure measure STRING STRING INTEGER ')' { CreateNewPin(yyElement, OU ($3), OU ($4), OU ($5), 2*GROUNDPLANEFRAME, OU ($5) + 2*MASKFRAME, OU ($6), $7, $8, OldFlags($9)); free ($7); free ($8); } ; pin_newformat /* x, y, thickness, drilling hole, name, flags */ : T_PIN '(' measure measure measure measure STRING INTEGER ')' { char p_number[8]; sprintf(p_number, "%d", pin_num++); CreateNewPin(yyElement, OU ($3), OU ($4), OU ($5), 2*GROUNDPLANEFRAME, OU ($5) + 2*MASKFRAME, OU ($6), $7, p_number, OldFlags($8)); free ($7); } ; pin_oldformat /* old format: x, y, thickness, name, flags * drilling hole is 40% of the diameter */ : T_PIN '(' measure measure measure STRING INTEGER ')' { Coord hole = OU ($5) * DEFAULT_DRILLINGHOLE; char p_number[8]; sprintf(p_number, "%d", pin_num++); CreateNewPin(yyElement, OU ($3), OU ($4), OU ($5), 2*GROUNDPLANEFRAME, OU ($5) + 2*MASKFRAME, hole, $6, p_number, OldFlags($7)); free ($6); } ; /* %start-doc pcbfile Pad @noindent Current syntax: @syntax Pad [rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" SFlags] @end syntax @noindent Legacy syntax: @syntax Pad (rX1 rY1 rX2 rY2 Thickness Clearance Mask "Name" "Number" NFlags) Pad (aX1 aY1 aX2 aY2 Thickness "Name" "Number" NFlags) Pad (aX1 aY1 aX2 aY2 Thickness "Name" NFlags) @end syntax @table @var @item rX1 rY1 rX2 rY2 Coordinates of the endpoints of the pad, relative to the element's mark. Note that the copper extends beyond these coordinates by half the thickness. To make a square or round pad, specify the same coordinate twice. @item aX1 aY1 aX2 aY2 Same, but absolute coordinates of the endpoints of the pad. @item Thickness width of the pad. @item Clearance add to thickness to get clearance width. @item Mask width of solder mask opening. @item Name name of pin @item Number number of pin @item SFlags symbolic or numerical flags @item NFlags numerical flags only @end table %end-doc */ pad_hi_format /* x1, y1, x2, y2, thickness, clearance, mask, name , pad number, flags */ : T_PAD '[' measure measure measure measure measure measure measure STRING STRING flags ']' { CreateNewPad(yyElement, NU ($3) + yyElement->MarkX, NU ($4) + yyElement->MarkY, NU ($5) + yyElement->MarkX, NU ($6) + yyElement->MarkY, NU ($7), NU ($8), NU ($9), $10, $11, $12); free ($10); free ($11); } ; pad_1.7_format /* x1, y1, x2, y2, thickness, clearance, mask, name , pad number, flags */ : T_PAD '(' measure measure measure measure measure measure measure STRING STRING INTEGER ')' { CreateNewPad(yyElement,OU ($3) + yyElement->MarkX, OU ($4) + yyElement->MarkY, OU ($5) + yyElement->MarkX, OU ($6) + yyElement->MarkY, OU ($7), OU ($8), OU ($9), $10, $11, OldFlags($12)); free ($10); free ($11); } ; pad_newformat /* x1, y1, x2, y2, thickness, name , pad number, flags */ : T_PAD '(' measure measure measure measure measure STRING STRING INTEGER ')' { CreateNewPad(yyElement,OU ($3),OU ($4),OU ($5),OU ($6),OU ($7), 2*GROUNDPLANEFRAME, OU ($7) + 2*MASKFRAME, $8, $9, OldFlags($10)); free ($8); free ($9); } ; pad /* x1, y1, x2, y2, thickness, name and flags */ : T_PAD '(' measure measure measure measure measure STRING INTEGER ')' { char p_number[8]; sprintf(p_number, "%d", pin_num++); CreateNewPad(yyElement,OU ($3),OU ($4),OU ($5),OU ($6),OU ($7), 2*GROUNDPLANEFRAME, OU ($7) + 2*MASKFRAME, $8,p_number, OldFlags($9)); free ($8); } ; flags : INTEGER { $$ = OldFlags($1); } | STRING { $$ = string_to_flags ($1, yyerror); free($1); } ; symbols : symbol | symbols symbol ; /* %start-doc pcbfile Symbol @noindent Current syntax: @syntax Symbol [Char Delta] ( @ @ @ @dots{} symbol lines @dots{} ) @end syntax @noindent Legacy syntax: @syntax Symbol (Char Delta) ( @ @ @ @dots{} symbol lines @dots{} ) @end syntax @table @var @item Char The character or numerical character value this symbol represents. Characters must be in single quotes. @item Delta Additional space to allow after this character. @end table %end-doc */ symbol : symbolhead symboldata ')' symbolhead : T_SYMBOL '[' symbolid measure ']' '(' { if ($3 <= 0 || $3 > MAX_FONTPOSITION) { yyerror("fontposition out of range"); YYABORT; } Symbol = &yyFont->Symbol[$3]; if (Symbol->Valid) { yyerror("symbol ID used twice"); YYABORT; } Symbol->Valid = true; Symbol->Delta = NU ($4); } | T_SYMBOL '(' symbolid measure ')' '(' { if ($3 <= 0 || $3 > MAX_FONTPOSITION) { yyerror("fontposition out of range"); YYABORT; } Symbol = &yyFont->Symbol[$3]; if (Symbol->Valid) { yyerror("symbol ID used twice"); YYABORT; } Symbol->Valid = true; Symbol->Delta = OU ($4); } ; symbolid : INTEGER | CHAR_CONST ; symboldata : /* empty */ | symboldata symboldefinition | symboldata hiressymbol ; /* %start-doc pcbfile SymbolLine @noindent Current syntax: @syntax SymbolLine [X1 Y1 X2 Y2 Thickness] @end syntax @noindent Legacy syntax: @syntax SymbolLine (X1 Y1 X2 Y2 Thickness) @end syntax @table @var @item X1 Y1 X2 Y2 The endpoints of this line. @item Thickness The width of this line. @end table %end-doc */ symboldefinition /* x1, y1, x2, y2, thickness */ : T_SYMBOLLINE '(' measure measure measure measure measure ')' { CreateNewLineInSymbol(Symbol, OU ($3), OU ($4), OU ($5), OU ($6), OU ($7)); } ; hiressymbol /* x1, y1, x2, y2, thickness */ : T_SYMBOLLINE '[' measure measure measure measure measure ']' { CreateNewLineInSymbol(Symbol, NU ($3), NU ($4), NU ($5), NU ($6), NU ($7)); } ; /* %start-doc pcbfile Netlist @syntax Netlist ( ) ( @ @ @ @dots{} nets @dots{} ) @end syntax %end-doc */ pcbnetlist : pcbnetdef | ; pcbnetdef /* net(...) net(...) ... */ : T_NETLIST '(' ')' '(' nets ')' ; nets : netdefs | ; netdefs : net | netdefs net ; /* %start-doc pcbfile Net @syntax Net ("Name" "Style") ( @ @ @ @dots{} connects @dots{} ) @end syntax @table @var @item Name The name of this net. @item Style The routing style that should be used when autorouting this net. @end table %end-doc */ net /* name style pin pin ... */ : T_NET '(' STRING STRING ')' '(' { Menu = CreateNewNet(&yyPCB->NetlistLib, $3, $4); free ($3); free ($4); } connections ')' ; connections : conndefs | ; conndefs : conn | conndefs conn ; /* %start-doc pcbfile Connect @syntax Connect ("PinPad") @end syntax @table @var @item PinPad The name of a pin or pad which is included in this net. Pin and Pad names are named by the refdes and pin name, like @code{"U14-7"} for pin 7 of U14, or @code{"T4-E"} for pin E of T4. @end table %end-doc */ conn : T_CONN '(' STRING ')' { CreateNewConnection(Menu, $3); free ($3); } ; /* %start-doc pcbfile Attribute @syntax Attribute ("Name" "Value") @end syntax Attributes allow boards and elements to have arbitrary data attached to them, which may or may not be used by PCB itself, but may be of use by other programs or users. @table @var @item Name The name of the attribute @item Value The value of the attribute. Values are always stored as strings, even if the value is interpreted as, for example, a number. @end table Below are some examples of global (board wide) attributes: @example Attribute("PCB::grid::unit" "mil") Attribute("PCB::grid::size" "39.37mil") Attribute("PCB::grid::unit" "mm") @end example and some examples for attributes in an element (local): @example Element["lock" "BGA676N100P26X26-2700X2700X260" "U?" "FG676" 20.0000mm 20.0000mm 0.0000 -631.49mil 0 100 ""] ( Attribute("author" "PCB Contributors") Attribute("dist-license" "GPL2") Attribute("use-license" "unlimited2") Attribute("status" "Experimental") Attribute("attributes in footprint" "1") Attribute("package body length" "27.000000") Attribute("package body width" "27.000000") Attribute("package height" "2.600000") @end example %end-doc */ attribute : T_ATTRIBUTE '(' STRING STRING ')' { CreateNewAttribute (attr_list, $3, $4 ? $4 : (char *)""); free ($3); free ($4); } ; opt_string : STRING { $$ = $1; } | /* empty */ { $$ = 0; } ; number : FLOATING { $$ = $1; } | INTEGER { $$ = $1; } ; measure /* Default unit (no suffix) is cmil */ : number { do_measure(&$$, $1, MIL_TO_COORD ($1) / 100.0, 0); } | number T_UMIL { M ($$, $1, MIL_TO_COORD ($1) / 1000000.0); } | number T_CMIL { M ($$, $1, MIL_TO_COORD ($1) / 100.0); } | number T_MIL { M ($$, $1, MIL_TO_COORD ($1)); } | number T_IN { M ($$, $1, INCH_TO_COORD ($1)); } | number T_NM { M ($$, $1, MM_TO_COORD ($1) / 1000000.0); } | number T_PX { M ($$, $1, MM_TO_COORD ($1) / 1000000.0); } | number T_UM { M ($$, $1, MM_TO_COORD ($1) / 1000.0); } | number T_MM { M ($$, $1, MM_TO_COORD ($1)); } | number T_M { M ($$, $1, MM_TO_COORD ($1) * 1000.0); } | number T_KM { M ($$, $1, MM_TO_COORD ($1) * 1000000.0); } ; %% /* --------------------------------------------------------------------------- * error routine called by parser library */ int yyerror(const char * s) { Message(_("ERROR parsing file '%s'\n" " line: %i\n" " description: '%s'\n"), yyfilename, yylineno, s); return(0); } int yywrap() { return 1; } static int check_file_version (int ver) { if ( ver > PCB_FILE_VERSION ) { Message (_("ERROR: The file you are attempting to load is in a format\n" "which is too new for this version of pcb. To load this file\n" "you need a version of pcb which is >= %d. If you are\n" "using a version built from git source, the source date\n" "must be >= %d. This copy of pcb can only read files\n" "up to file version %d.\n"), ver, ver, PCB_FILE_VERSION); return 1; } return 0; } static void do_measure (PLMeasure *m, Coord i, double d, int u) { m->ival = i; m->bval = round (d); m->dval = d; m->has_units = u; } static int integer_value (PLMeasure m) { if (m.has_units) yyerror("units ignored here"); return m.ival; } static Coord old_units (PLMeasure m) { if (m.has_units) return m.bval; return round (MIL_TO_COORD (m.ival)); } static Coord new_units (PLMeasure m) { if (m.has_units) return m.bval; return round (MIL_TO_COORD (m.ival) / 100.0); } pcb-4.2.2/src/parse_l.c0000664000076400007640000017436013434562753011625 00000000000000 #line 3 "parse_l.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 35 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires * access to the local variable yy_act. Since yyless() is a macro, it would break * existing scanners that call yyless() from OUTSIDE yylex. * One obvious solution it to make yy_act a global. I tried that, and saw * a 5% performance hit in a non-yylineno scanner, because yy_act is * normally declared as a register variable-- so it is not worth it. */ #define YY_LESS_LINENO(n) \ do { \ int yyl;\ for ( yyl = n; yyl < yyleng; ++yyl )\ if ( yytext[yyl] == '\n' )\ --yylineno;\ }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 52 #define YY_END_OF_BUFFER 53 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[192] = { 0, 0, 0, 53, 51, 48, 49, 50, 51, 47, 51, 51, 43, 44, 44, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 35, 51, 51, 51, 48, 0, 46, 0, 47, 0, 44, 44, 43, 43, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 36, 0, 34, 32, 41, 33, 42, 45, 27, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 2, 11, 10, 0, 14, 0, 0, 0, 0, 0, 12, 0, 39, 0, 0, 0, 0, 0, 0, 0, 3, 0, 26, 0, 13, 22, 0, 0, 0, 0, 0, 16, 0, 38, 37, 0, 0, 0, 0, 0, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 23, 0, 0, 0, 0, 24, 21, 0, 0, 30, 19, 0, 28, 0, 25, 0, 0, 5, 0, 0, 0, 0, 6, 0, 0, 31, 0, 0, 0, 15, 0, 18, 0, 0, 20, 17, 1, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 5, 6, 1, 1, 1, 7, 1, 1, 1, 8, 1, 8, 9, 1, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 1, 1, 1, 1, 1, 1, 1, 12, 13, 14, 15, 16, 17, 18, 19, 1, 1, 1, 20, 21, 22, 1, 23, 1, 24, 25, 26, 1, 27, 1, 1, 1, 1, 1, 28, 1, 1, 1, 1, 29, 30, 31, 32, 33, 34, 35, 36, 37, 1, 38, 39, 40, 41, 42, 43, 1, 44, 45, 46, 47, 1, 1, 48, 49, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[50] = { 0, 1, 1, 2, 3, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int16_t yy_base[196] = { 0, 0, 0, 227, 228, 224, 228, 228, 45, 0, 0, 41, 43, 46, 47, 15, 18, 201, 185, 25, 179, 180, 34, 192, 187, 53, 37, 23, 41, 182, 178, 176, 176, 38, 175, 166, 173, 210, 63, 228, 207, 0, 203, 200, 70, 73, 75, 0, 78, 177, 161, 165, 161, 190, 170, 163, 172, 55, 161, 150, 157, 153, 150, 182, 162, 152, 153, 145, 159, 140, 148, 139, 153, 156, 147, 228, 228, 144, 228, 228, 228, 145, 228, 0, 228, 137, 139, 134, 228, 138, 144, 141, 143, 127, 140, 139, 138, 132, 149, 228, 228, 228, 119, 228, 121, 127, 135, 118, 119, 228, 123, 228, 122, 123, 126, 116, 124, 129, 110, 228, 111, 228, 109, 228, 228, 115, 64, 122, 117, 107, 228, 108, 228, 228, 117, 115, 101, 103, 110, 228, 97, 228, 96, 96, 97, 97, 92, 97, 106, 87, 87, 228, 86, 87, 228, 84, 96, 87, 92, 228, 106, 86, 78, 228, 81, 78, 228, 93, 228, 82, 83, 228, 86, 74, 80, 79, 228, 82, 73, 228, 80, 66, 62, 228, 70, 228, 67, 57, 228, 228, 228, 228, 101, 105, 109, 92 } ; static yyconst flex_int16_t yy_def[196] = { 0, 191, 1, 191, 191, 191, 191, 191, 192, 193, 194, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 192, 191, 192, 193, 191, 191, 191, 191, 191, 195, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 195, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 0, 191, 191, 191, 191 } ; static yyconst flex_int16_t yy_nxt[278] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 4, 4, 4, 30, 4, 4, 4, 4, 4, 31, 32, 4, 33, 34, 4, 35, 4, 4, 4, 36, 4, 4, 39, 43, 44, 45, 45, 46, 46, 48, 48, 49, 51, 50, 55, 59, 56, 52, 67, 63, 39, 69, 68, 60, 70, 40, 71, 77, 143, 72, 78, 46, 48, 48, 64, 45, 45, 45, 45, 46, 48, 48, 65, 40, 92, 173, 47, 66, 83, 93, 190, 144, 189, 174, 38, 188, 187, 38, 41, 186, 41, 41, 42, 185, 42, 42, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 91, 90, 89, 88, 87, 86, 85, 84, 46, 82, 38, 37, 81, 80, 79, 76, 75, 74, 73, 62, 61, 58, 57, 54, 53, 37, 191, 3, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191 } ; static yyconst flex_int16_t yy_chk[278] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 11, 11, 12, 12, 13, 14, 14, 14, 15, 16, 15, 19, 22, 19, 16, 26, 25, 38, 27, 26, 22, 27, 8, 28, 33, 126, 28, 33, 44, 44, 44, 25, 45, 45, 46, 46, 48, 48, 48, 25, 38, 57, 164, 13, 25, 195, 57, 187, 126, 186, 164, 192, 184, 182, 192, 193, 181, 193, 193, 194, 180, 194, 194, 178, 177, 175, 174, 173, 172, 170, 169, 167, 165, 162, 161, 160, 158, 157, 156, 155, 153, 152, 150, 149, 148, 147, 146, 145, 144, 143, 142, 140, 138, 137, 136, 135, 134, 131, 129, 128, 127, 125, 122, 120, 118, 117, 116, 115, 114, 113, 112, 110, 108, 107, 106, 105, 104, 102, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 87, 86, 85, 81, 77, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 56, 55, 54, 53, 52, 51, 50, 49, 43, 42, 40, 37, 36, 35, 34, 32, 31, 30, 29, 24, 23, 21, 20, 18, 17, 5, 3, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191 } ; /* Table of booleans, true if rule could match eol. */ static yyconst flex_int32_t yy_rule_can_match_eol[53] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, }; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "parse_l.l" #line 2 "parse_l.l" /* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996,2006 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * */ /* lexical definitions to parse ASCII input of PCB and Element description */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #if defined(_POSIX_SOURCE) || defined(_HPUX_SOURCE) #include #endif #include "global.h" #ifdef HAVE_LIBDMALLOC # include /* see http://dmalloc.com */ #endif #include "global.h" #include "crosshair.h" #include "data.h" #include "error.h" #include "file.h" #include "mymem.h" #include "misc.h" #include "strflags.h" #include "parse_l.h" #include "parse_y.h" #include "create.h" #define YY_NO_INPUT /* --------------------------------------------------------------------------- * some shared parser identifiers */ #ifdef FLEX_SCANNER #define yyunput ATTRIBUTE_UNUSED yyunput #endif char *yyfilename; /* in this file */ PCBType *yyPCB; /* used by parser */ DataType *yyData; ElementType *yyElement; FontType *yyFont; static int parse_number (void); /* --------------------------------------------------------------------------- * an external prototypes */ int yyparse(void); /* --------------------------------------------------------------------------- * some local prototypes */ static int Parse(char *, char *, char *, char *); #line 682 "parse_l.c" #define INITIAL 0 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy (void ); int yyget_debug (void ); void yyset_debug (int debug_flag ); YY_EXTRA_TYPE yyget_extra (void ); void yyset_extra (YY_EXTRA_TYPE user_defined ); FILE *yyget_in (void ); void yyset_in (FILE * in_str ); FILE *yyget_out (void ); void yyset_out (FILE * out_str ); int yyget_leng (void ); char *yyget_text (void ); int yyget_lineno (void ); void yyset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif static void yyunput (int c,char *buf_ptr ); #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ unsigned n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 98 "parse_l.l" #line 867 "parse_l.c" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 192 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 228 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) { int yyl; for ( yyl = 0; yyl < yyleng; ++yyl ) if ( yytext[yyl] == '\n' ) yylineno++; ; } do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 100 "parse_l.l" { return(T_FILEVERSION); } YY_BREAK case 2: YY_RULE_SETUP #line 101 "parse_l.l" { return(T_PCB); } YY_BREAK case 3: YY_RULE_SETUP #line 102 "parse_l.l" { return(T_GRID); } YY_BREAK case 4: YY_RULE_SETUP #line 103 "parse_l.l" { return(T_CURSOR); } YY_BREAK case 5: YY_RULE_SETUP #line 104 "parse_l.l" { return(T_THERMAL); } YY_BREAK case 6: YY_RULE_SETUP #line 105 "parse_l.l" { return(T_AREA); } YY_BREAK case 7: YY_RULE_SETUP #line 106 "parse_l.l" { return(T_DRC); } YY_BREAK case 8: YY_RULE_SETUP #line 107 "parse_l.l" { return(T_FLAGS); } YY_BREAK case 9: YY_RULE_SETUP #line 108 "parse_l.l" { return(T_LAYER); } YY_BREAK case 10: YY_RULE_SETUP #line 109 "parse_l.l" { return(T_PIN); } YY_BREAK case 11: YY_RULE_SETUP #line 110 "parse_l.l" { return(T_PAD); } YY_BREAK case 12: YY_RULE_SETUP #line 111 "parse_l.l" { return(T_VIA); } YY_BREAK case 13: YY_RULE_SETUP #line 112 "parse_l.l" { return(T_LINE); } YY_BREAK case 14: YY_RULE_SETUP #line 113 "parse_l.l" { return(T_RAT); } YY_BREAK case 15: YY_RULE_SETUP #line 114 "parse_l.l" { return(T_RECTANGLE); } YY_BREAK case 16: YY_RULE_SETUP #line 115 "parse_l.l" { return(T_TEXT); } YY_BREAK case 17: YY_RULE_SETUP #line 116 "parse_l.l" { return(T_ELEMENTLINE); } YY_BREAK case 18: YY_RULE_SETUP #line 117 "parse_l.l" { return(T_ELEMENTARC); } YY_BREAK case 19: YY_RULE_SETUP #line 118 "parse_l.l" { return(T_ELEMENT); } YY_BREAK case 20: YY_RULE_SETUP #line 119 "parse_l.l" { return(T_SYMBOLLINE); } YY_BREAK case 21: YY_RULE_SETUP #line 120 "parse_l.l" { return(T_SYMBOL); } YY_BREAK case 22: YY_RULE_SETUP #line 121 "parse_l.l" { return(T_MARK); } YY_BREAK case 23: YY_RULE_SETUP #line 122 "parse_l.l" { return(T_GROUPS); } YY_BREAK case 24: YY_RULE_SETUP #line 123 "parse_l.l" { return(T_STYLES); } YY_BREAK case 25: YY_RULE_SETUP #line 124 "parse_l.l" { return(T_POLYGON); } YY_BREAK case 26: YY_RULE_SETUP #line 125 "parse_l.l" { return(T_POLYGON_HOLE); } YY_BREAK case 27: YY_RULE_SETUP #line 126 "parse_l.l" { return(T_ARC); } YY_BREAK case 28: YY_RULE_SETUP #line 127 "parse_l.l" { return(T_NETLIST); } YY_BREAK case 29: YY_RULE_SETUP #line 128 "parse_l.l" { return(T_NET); } YY_BREAK case 30: YY_RULE_SETUP #line 129 "parse_l.l" { return(T_CONN); } YY_BREAK case 31: YY_RULE_SETUP #line 130 "parse_l.l" { return(T_ATTRIBUTE); } YY_BREAK case 32: YY_RULE_SETUP #line 132 "parse_l.l" { return T_NM; } YY_BREAK case 33: YY_RULE_SETUP #line 133 "parse_l.l" { return T_UM; } YY_BREAK case 34: YY_RULE_SETUP #line 134 "parse_l.l" { return T_MM; } YY_BREAK case 35: YY_RULE_SETUP #line 135 "parse_l.l" { return T_M; } YY_BREAK case 36: YY_RULE_SETUP #line 136 "parse_l.l" { return T_KM; } YY_BREAK case 37: YY_RULE_SETUP #line 137 "parse_l.l" { return T_UMIL; } YY_BREAK case 38: YY_RULE_SETUP #line 138 "parse_l.l" { return T_CMIL; } YY_BREAK case 39: YY_RULE_SETUP #line 139 "parse_l.l" { return T_MIL; } YY_BREAK case 40: YY_RULE_SETUP #line 140 "parse_l.l" { return T_IN; } YY_BREAK case 41: YY_RULE_SETUP #line 141 "parse_l.l" { return T_PX; } YY_BREAK case 42: YY_RULE_SETUP #line 143 "parse_l.l" { yylval.integer = (unsigned) *(yytext+1); return(CHAR_CONST); } YY_BREAK case 43: YY_RULE_SETUP #line 147 "parse_l.l" { return parse_number(); } YY_BREAK case 44: YY_RULE_SETUP #line 148 "parse_l.l" { yylval.integer = round (g_ascii_strtod (yytext, NULL)); return INTEGER; } YY_BREAK case 45: YY_RULE_SETUP #line 150 "parse_l.l" { unsigned n; sscanf((char *) yytext, "%x", &n); yylval.integer = n; return INTEGER; } YY_BREAK case 46: YY_RULE_SETUP #line 155 "parse_l.l" { char *p1, *p2; /* return NULL on empty string */ if (yyleng == 2) { yylval.string = NULL; return(STRING); } /* allocate memory and copy string; * stringlength is counted and copied without * leading and trailing '"' */ yyleng -= 2; yylval.string = (char *)calloc (yyleng+1, sizeof (char)); p1 = (char *) (yytext +1); p2 = yylval.string; while(yyleng--) { /* check for special character */ if (*p1 == '\\') { yyleng--; p1++; } *p2++ = *p1++; } *p2 = '\0'; return(STRING); } YY_BREAK case 47: YY_RULE_SETUP #line 187 "parse_l.l" {} YY_BREAK case 48: YY_RULE_SETUP #line 188 "parse_l.l" {} YY_BREAK case 49: /* rule 49 can match eol */ YY_RULE_SETUP #line 189 "parse_l.l" { #ifndef FLEX_SCANNER yylineno++; #endif } YY_BREAK case 50: YY_RULE_SETUP #line 194 "parse_l.l" {} YY_BREAK case 51: YY_RULE_SETUP #line 195 "parse_l.l" { return(*yytext); } YY_BREAK case 52: YY_RULE_SETUP #line 197 "parse_l.l" ECHO; YY_BREAK #line 1263 "parse_l.c" case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), (size_t) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 192 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 192 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 191); return yy_is_jam ? 0 : yy_current_state; } static void yyunput (int c, register char * yy_bp ) { register char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = (yy_n_chars) + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; if ( c == '\n' ){ --yylineno; } (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); if ( c == '\n' ) yylineno++; ; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { return yy_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param line_number * */ void yyset_lineno (int line_number ) { yylineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str ) { yyin = in_str ; } void yyset_out (FILE * out_str ) { yyout = out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int bdebug ) { yy_flex_debug = bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ /* We do not touch yylineno unless the option is enabled. */ yylineno = 1; (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 197 "parse_l.l" /* --------------------------------------------------------------------------- * sets up the preprocessor command */ static int Parse(char *Executable, char *Path, char *Filename, char *Parameter) { static char *command = NULL; int returncode; int used_popen = 0; char *tmps; size_t l; #ifdef FLEX_SCANNER static bool firsttime = true; #endif if (EMPTY_STRING_P (Executable)) { l = 2; if ( Path != NULL ) l += strlen (Path); l += strlen (Filename); if ( (tmps = (char *) malloc ( l * sizeof (char))) == NULL) { fprintf (stderr, "Parse(): malloc failed\n"); exit (1); } if ( Path != NULL && *Path != '\0') sprintf (tmps, "%s%s%s", Path, PCB_DIR_SEPARATOR_S, Filename); else sprintf (tmps, "%s", Filename); yyin = fopen (tmps, "r"); if (!yyin) { /* Special case this one, we get it all the time... */ if (strcmp (tmps, "./default_font")) Message("Can't open %s for reading\n", tmps); return(1); } free (tmps); } else { used_popen = 1; /* release old command and create new from template */ free (command); command = EvaluateFilename(Executable, Path, Filename, Parameter); /* open pipe to stdout of command */ if (*command == '\0' || (yyin = popen(command, "r")) == NULL) { PopenErrorMessage(command); return(1); } } #ifdef FLEX_SCANNER /* reset parser if not called the first time */ if (!firsttime) yyrestart(yyin); firsttime = false; #endif /* init linenumber and filename for yyerror() */ yylineno = 1; yyfilename = Filename; /* We need to save the data temporarily because lex-yacc are able * to break the application if the input file has an illegal format. * It's not necessary if the system supports the call of functions * on termination. */ CreateBeLenient (true); #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT) if (PCB && PCB->Data) SaveTMPData(); returncode = yyparse(); RemoveTMPData(); #else returncode = yyparse(); #endif /* clean up parse buffer */ yy_delete_buffer(YY_CURRENT_BUFFER); CreateBeLenient (false); if (used_popen) return(pclose(yyin) ? 1 : returncode); return(fclose(yyin) ? 1 : returncode); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a single element file */ int ParseElementFile (DataType *Ptr, char *Filename) { yyPCB = NULL; yyData = Ptr; yyFont = &PCB->Font; yyElement = NULL; return(Parse(NULL,NULL,Filename,NULL)); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a single library entry */ int ParseLibraryEntry (DataType *Ptr, char *Template) { yyPCB = NULL; yyData = Ptr; yyFont = &PCB->Font; yyElement = NULL; return(Parse(Settings.LibraryCommand, Settings.LibraryPath, Settings.LibraryFilename, Template)); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a complete board */ int ParsePCB (PCBType *Ptr, char *Filename) { yyPCB = Ptr; yyData = NULL; yyFont = NULL; yyElement = NULL; return(Parse(Settings.FileCommand, Settings.FilePath, Filename, NULL)); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a font */ int ParseFont (FontType *Ptr, char *Filename) { int r = 0; char *path, *p; yyPCB = NULL; yyFont = Ptr; yyElement = NULL; path = strdup (Settings.FontPath); /* search through the font path for a font file */ for (p = strtok (path, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER)) { #ifdef DEBUG Message ("Looking for %s in %s\n", Filename, p); #endif r = Parse(Settings.FontCommand, p, Filename, NULL); if (r == 0) { #ifdef DEBUG Message ("Found %s in %s\n", Filename, p); #endif break; } } free (path); return r; } static int parse_number () { yylval.number = g_ascii_strtod ((gchar *) yytext, NULL); return FLOATING; } pcb-4.2.2/src/misc.c0000664000076400007640000021750313604156111011112 00000000000000/*! * \file src/misc.c * * \brief Misc functions used by several modules. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996,2004,2006 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_PWD_H #include #endif #include "global.h" #include "box.h" #include "crosshair.h" #include "create.h" #include "data.h" #include "draw.h" #include "file.h" #include "error.h" #include "mymem.h" #include "misc.h" #include "move.h" #include "pcb-printf.h" #include "polygon.h" #include "remove.h" #include "rtree.h" #include "rotate.h" #include "rubberband.h" #include "search.h" #include "set.h" #include "undo.h" #include "action.h" #ifdef HAVE_LIBDMALLOC #include #endif /* forward declarations */ static char *BumpName (char *); static void GetGridLockCoordinates (int, void *, void *, void *, Coord *, Coord *); /* Local variables */ /*! * \brief Used by SaveStackAndVisibility() and * RestoreStackAndVisibility(). */ static struct { bool ElementOn, InvisibleObjectsOn, PinOn, ViaOn, RatOn; int LayerStack[MAX_ALL_LAYER]; bool LayerOn[MAX_ALL_LAYER]; int cnt; } SavedStack; /*! * \brief Distance() should be used so that there is only one place to * deal with overflow/precision errors. */ double Distance (double x1, double y1, double x2, double y2) { return hypot(x2 - x1, y2 - y1); } /*! * \brief Bring an angle into [0, 360] range. */ Angle NormalizeAngle (Angle a) { while (a < 0) a += 360.0; while (a >= 360.0) a -= 360.0; return a; } /*! * \brief GetValue() returns a numeric value passed from the string and * sets the bool variable absolute to false if it leads with a +/- * character. */ double GetValue (const char *val, const char *units, bool * absolute) { return GetValueEx(val, units, absolute, NULL, "cmil"); } double GetValueEx (const char *val, const char *units, bool * absolute, UnitList extra_units, const char *default_unit) { double value; int n = -1; bool scaled = 0; bool dummy; /* Allow NULL to be passed for absolute */ if(absolute == NULL) absolute = &dummy; /* if the first character is a sign we have to add the * value to the current one */ if (*val == '=') { *absolute = true; if (sscanf (val+1, "%lf%n", &value, &n) < 1) return 0; n++; } else { if (isdigit ((int) *val)) *absolute = true; else *absolute = false; if (sscanf (val, "%lf%n", &value, &n) < 1) return 0; } if (!units && n > 0) units = val + n; while (units && *units == ' ') units ++; if (units && *units) { int i; const Unit *unit = get_unit_struct (units); if (unit != NULL) { value = unit_to_coord (unit, value); scaled = 1; } if (extra_units) { for (i = 0; *extra_units[i].suffix; ++i) { if (strncmp (units, extra_units[i].suffix, strlen(extra_units[i].suffix)) == 0) { value *= extra_units[i].scale; if (extra_units[i].flags & UNIT_PERCENT) value /= 100.0; scaled = 1; } } } } /* Apply default unit */ if (!scaled && default_unit && *default_unit) { int i; const Unit *unit = get_unit_struct (default_unit); if (extra_units) for (i = 0; *extra_units[i].suffix; ++i) if (strcmp (extra_units[i].suffix, default_unit) == 0) { value *= extra_units[i].scale; if (extra_units[i].flags & UNIT_PERCENT) value /= 100.0; scaled = 1; } if (!scaled && unit != NULL) value = unit_to_coord (unit, value); } return value; } /*! * \brief Extract a unit-less value from a string. * * \param val String containing the value to be read. * * \param absolute Returns whether the returned value is an absolute one. * * \return The value read, with sign. * * This is the same as GetValue() and GetValueEx(), but totally ignoring units. * Typical application is a list selector, like the type of thermal to apply * to a pin. */ double GetUnitlessValue (const char *val, bool *absolute) { double value; if (*val == '=') { *absolute = true; val++; } else { if (isdigit ((int) *val)) *absolute = true; else *absolute = false; } if (sscanf (val, "%lf", &value) < 1) return 0.; return value; } /*! * \brief Sets the bounding box of a point (which is silly). */ void SetPointBoundingBox (PointType *Pnt) { Pnt->X2 = Pnt->X + 1; Pnt->Y2 = Pnt->Y + 1; } /*! * \brief Sets the bounding box of a pin or via. */ void SetPinBoundingBox (PinType *Pin) { Coord width; /* the bounding box covers the extent of influence * so it must include the clearance values too */ width = MAX (Pin->Clearance + PIN_SIZE (Pin), Pin->Mask) / 2; /* Adjust for our discrete polygon approximation */ width = (double)width * POLY_CIRC_RADIUS_ADJ + 0.5; Pin->BoundingBox.X1 = Pin->X - width; Pin->BoundingBox.Y1 = Pin->Y - width; Pin->BoundingBox.X2 = Pin->X + width; Pin->BoundingBox.Y2 = Pin->Y + width; close_box(&Pin->BoundingBox); } /*! * \brief Sets the bounding box of a pad. */ void SetPadBoundingBox (PadType *Pad) { Coord width; Coord deltax; Coord deltay; /* the bounding box covers the extent of influence * so it must include the clearance values too */ width = (Pad->Thickness + Pad->Clearance + 1) / 2; width = MAX (width, (Pad->Mask + 1) / 2); deltax = Pad->Point2.X - Pad->Point1.X; deltay = Pad->Point2.Y - Pad->Point1.Y; if (TEST_FLAG (SQUAREFLAG, Pad) && deltax != 0 && deltay != 0) { /* slanted square pad */ double theta; Coord btx, bty; /* T is a vector half a thickness long, in the direction of one of the corners. */ theta = atan2 (deltay, deltax); btx = width * cos (theta + M_PI/4) * sqrt(2.0); bty = width * sin (theta + M_PI/4) * sqrt(2.0); Pad->BoundingBox.X1 = MIN (MIN (Pad->Point1.X - btx, Pad->Point1.X - bty), MIN (Pad->Point2.X + btx, Pad->Point2.X + bty)); Pad->BoundingBox.X2 = MAX (MAX (Pad->Point1.X - btx, Pad->Point1.X - bty), MAX (Pad->Point2.X + btx, Pad->Point2.X + bty)); Pad->BoundingBox.Y1 = MIN (MIN (Pad->Point1.Y + btx, Pad->Point1.Y - bty), MIN (Pad->Point2.Y - btx, Pad->Point2.Y + bty)); Pad->BoundingBox.Y2 = MAX (MAX (Pad->Point1.Y + btx, Pad->Point1.Y - bty), MAX (Pad->Point2.Y - btx, Pad->Point2.Y + bty)); } else { /* Adjust for our discrete polygon approximation */ width = (double)width * POLY_CIRC_RADIUS_ADJ + 0.5; Pad->BoundingBox.X1 = MIN (Pad->Point1.X, Pad->Point2.X) - width; Pad->BoundingBox.X2 = MAX (Pad->Point1.X, Pad->Point2.X) + width; Pad->BoundingBox.Y1 = MIN (Pad->Point1.Y, Pad->Point2.Y) - width; Pad->BoundingBox.Y2 = MAX (Pad->Point1.Y, Pad->Point2.Y) + width; } close_box(&Pad->BoundingBox); } /*! * \brief Sets the bounding box of a line. */ void SetLineBoundingBox (LineType *Line) { Coord width = (Line->Thickness + Line->Clearance + 1) / 2; /* Adjust for our discrete polygon approximation */ width = (double)width * POLY_CIRC_RADIUS_ADJ + 0.5; Line->BoundingBox.X1 = MIN (Line->Point1.X, Line->Point2.X) - width; Line->BoundingBox.X2 = MAX (Line->Point1.X, Line->Point2.X) + width; Line->BoundingBox.Y1 = MIN (Line->Point1.Y, Line->Point2.Y) - width; Line->BoundingBox.Y2 = MAX (Line->Point1.Y, Line->Point2.Y) + width; close_box(&Line->BoundingBox); SetPointBoundingBox (&Line->Point1); SetPointBoundingBox (&Line->Point2); } /*! * \brief Sets the bounding box of a polygons. */ void SetPolygonBoundingBox (PolygonType *Polygon) { Polygon->BoundingBox.X1 = Polygon->BoundingBox.Y1 = MAX_COORD; Polygon->BoundingBox.X2 = Polygon->BoundingBox.Y2 = 0; POLYGONPOINT_LOOP (Polygon); { MAKEMIN (Polygon->BoundingBox.X1, point->X); MAKEMIN (Polygon->BoundingBox.Y1, point->Y); MAKEMAX (Polygon->BoundingBox.X2, point->X); MAKEMAX (Polygon->BoundingBox.Y2, point->Y); } /* boxes don't include the lower right corner */ close_box(&Polygon->BoundingBox); END_LOOP; } /*! * \brief Sets the bounding box of an element. */ void SetElementBoundingBox (DataType *Data, ElementType *Element, FontType *Font) { BoxType *box, *vbox; if (Data && Data->element_tree) r_delete_entry (Data->element_tree, (BoxType *) Element); /* first update the text objects */ ELEMENTTEXT_LOOP (Element); { if (Data && Data->name_tree[n]) r_delete_entry (Data->name_tree[n], (BoxType *) text); SetTextBoundingBox (Font, text); if (Data && !Data->name_tree[n]) Data->name_tree[n] = r_create_tree (NULL, 0, 0); if (Data) r_insert_entry (Data->name_tree[n], (BoxType *) text, 0); } END_LOOP; /* do not include the elementnames bounding box which * is handled separately */ box = &Element->BoundingBox; vbox = &Element->VBox; box->X1 = box->Y1 = MAX_COORD; box->X2 = box->Y2 = 0; ELEMENTLINE_LOOP (Element); { SetLineBoundingBox (line); MAKEMIN (box->X1, line->Point1.X - (line->Thickness + 1) / 2); MAKEMIN (box->Y1, line->Point1.Y - (line->Thickness + 1) / 2); MAKEMIN (box->X1, line->Point2.X - (line->Thickness + 1) / 2); MAKEMIN (box->Y1, line->Point2.Y - (line->Thickness + 1) / 2); MAKEMAX (box->X2, line->Point1.X + (line->Thickness + 1) / 2); MAKEMAX (box->Y2, line->Point1.Y + (line->Thickness + 1) / 2); MAKEMAX (box->X2, line->Point2.X + (line->Thickness + 1) / 2); MAKEMAX (box->Y2, line->Point2.Y + (line->Thickness + 1) / 2); } END_LOOP; ARC_LOOP (Element); { SetArcBoundingBox (arc); MAKEMIN (box->X1, arc->BoundingBox.X1); MAKEMIN (box->Y1, arc->BoundingBox.Y1); MAKEMAX (box->X2, arc->BoundingBox.X2); MAKEMAX (box->Y2, arc->BoundingBox.Y2); } END_LOOP; *vbox = *box; PIN_LOOP (Element); { if (Data && Data->pin_tree) r_delete_entry (Data->pin_tree, (BoxType *) pin); SetPinBoundingBox (pin); if (Data) { if (!Data->pin_tree) Data->pin_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Data->pin_tree, (BoxType *) pin, 0); } MAKEMIN (box->X1, pin->BoundingBox.X1); MAKEMIN (box->Y1, pin->BoundingBox.Y1); MAKEMAX (box->X2, pin->BoundingBox.X2); MAKEMAX (box->Y2, pin->BoundingBox.Y2); MAKEMIN (vbox->X1, pin->X - pin->Thickness / 2); MAKEMIN (vbox->Y1, pin->Y - pin->Thickness / 2); MAKEMAX (vbox->X2, pin->X + pin->Thickness / 2); MAKEMAX (vbox->Y2, pin->Y + pin->Thickness / 2); } END_LOOP; PAD_LOOP (Element); { if (Data && Data->pad_tree) r_delete_entry (Data->pad_tree, (BoxType *) pad); SetPadBoundingBox (pad); if (Data) { if (!Data->pad_tree) Data->pad_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Data->pad_tree, (BoxType *) pad, 0); } MAKEMIN (box->X1, pad->BoundingBox.X1); MAKEMIN (box->Y1, pad->BoundingBox.Y1); MAKEMAX (box->X2, pad->BoundingBox.X2); MAKEMAX (box->Y2, pad->BoundingBox.Y2); MAKEMIN (vbox->X1, MIN (pad->Point1.X, pad->Point2.X) - pad->Thickness / 2); MAKEMIN (vbox->Y1, MIN (pad->Point1.Y, pad->Point2.Y) - pad->Thickness / 2); MAKEMAX (vbox->X2, MAX (pad->Point1.X, pad->Point2.X) + pad->Thickness / 2); MAKEMAX (vbox->Y2, MAX (pad->Point1.Y, pad->Point2.Y) + pad->Thickness / 2); } END_LOOP; /* now we set the EDGE2FLAG of the pad if Point2 * is closer to the outside edge than Point1 */ PAD_LOOP (Element); { if (pad->Point1.Y == pad->Point2.Y) { /* horizontal pad */ if (box->X2 - pad->Point2.X < pad->Point1.X - box->X1) SET_FLAG (EDGE2FLAG, pad); else CLEAR_FLAG (EDGE2FLAG, pad); } else { /* vertical pad */ if (box->Y2 - pad->Point2.Y < pad->Point1.Y - box->Y1) SET_FLAG (EDGE2FLAG, pad); else CLEAR_FLAG (EDGE2FLAG, pad); } } END_LOOP; /* mark pins with component orientation */ if ((box->X2 - box->X1) > (box->Y2 - box->Y1)) { PIN_LOOP (Element); { SET_FLAG (EDGE2FLAG, pin); } END_LOOP; } else { PIN_LOOP (Element); { CLEAR_FLAG (EDGE2FLAG, pin); } END_LOOP; } close_box(box); close_box(vbox); if (Data && !Data->element_tree) Data->element_tree = r_create_tree (NULL, 0, 0); if (Data) r_insert_entry (Data->element_tree, box, 0); } /*! * \brief Creates the bounding box of a text object. */ void SetTextBoundingBox (FontType *FontPtr, TextType *Text) { SymbolType *symbol = FontPtr->Symbol; unsigned char *s = (unsigned char *) Text->TextString; int i; int space; Coord minx, miny, maxx, maxy, tx; Coord min_final_radius; Coord min_unscaled_radius; bool first_time = true; minx = miny = maxx = maxy = tx = 0; /* Calculate the bounding box based on the larger of the thicknesses * the text might clamped at on silk or copper layers. */ min_final_radius = MAX (PCB->minWid, PCB->minSlk) / 2; /* Pre-adjust the line radius for the fact we are initially computing the * bounds of the un-scaled text, and the thickness clamping applies to * scaled text. */ min_unscaled_radius = UNSCALE_TEXT (min_final_radius, Text->Scale); /* calculate size of the bounding box */ for (; s && *s; s++) { if (*s <= MAX_FONTPOSITION && symbol[*s].Valid) { LineType *line = symbol[*s].Line; for (i = 0; i < symbol[*s].LineN; line++, i++) { /* Clamp the width of text lines at the minimum thickness. * NB: Divide 4 in thickness calculation is comprised of a factor * of 1/2 to get a radius from the center-line, and a factor * of 1/2 because some stupid reason we render our glyphs * at half their defined stroke-width. */ Coord unscaled_radius = MAX (min_unscaled_radius, line->Thickness / 4); if (first_time) { minx = maxx = line->Point1.X; miny = maxy = line->Point1.Y; first_time = false; } minx = MIN (minx, line->Point1.X - unscaled_radius + tx); miny = MIN (miny, line->Point1.Y - unscaled_radius); minx = MIN (minx, line->Point2.X - unscaled_radius + tx); miny = MIN (miny, line->Point2.Y - unscaled_radius); maxx = MAX (maxx, line->Point1.X + unscaled_radius + tx); maxy = MAX (maxy, line->Point1.Y + unscaled_radius); maxx = MAX (maxx, line->Point2.X + unscaled_radius + tx); maxy = MAX (maxy, line->Point2.Y + unscaled_radius); } space = symbol[*s].Delta; } else { BoxType *ds = &FontPtr->DefaultSymbol; Coord w = ds->X2 - ds->X1; minx = MIN (minx, ds->X1 + tx); miny = MIN (miny, ds->Y1); minx = MIN (minx, ds->X2 + tx); miny = MIN (miny, ds->Y2); maxx = MAX (maxx, ds->X1 + tx); maxy = MAX (maxy, ds->Y1); maxx = MAX (maxx, ds->X2 + tx); maxy = MAX (maxy, ds->Y2); space = w / 5; } tx += symbol[*s].Width + space; } /* scale values */ minx = SCALE_TEXT (minx, Text->Scale); miny = SCALE_TEXT (miny, Text->Scale); maxx = SCALE_TEXT (maxx, Text->Scale); maxy = SCALE_TEXT (maxy, Text->Scale); /* set upper-left and lower-right corner; * swap coordinates if necessary (origin is already in 'swapped') * and rotate box */ if (TEST_FLAG (ONSOLDERFLAG, Text)) { Text->BoundingBox.X1 = Text->X + minx; Text->BoundingBox.Y1 = Text->Y - miny; Text->BoundingBox.X2 = Text->X + maxx; Text->BoundingBox.Y2 = Text->Y - maxy; RotateBoxLowLevel (&Text->BoundingBox, Text->X, Text->Y, (4 - Text->Direction) & 0x03); } else { Text->BoundingBox.X1 = Text->X + minx; Text->BoundingBox.Y1 = Text->Y + miny; Text->BoundingBox.X2 = Text->X + maxx; Text->BoundingBox.Y2 = Text->Y + maxy; RotateBoxLowLevel (&Text->BoundingBox, Text->X, Text->Y, Text->Direction); } /* the bounding box covers the extent of influence * so it must include the clearance values too */ Text->BoundingBox.X1 -= PCB->Bloat; Text->BoundingBox.Y1 -= PCB->Bloat; Text->BoundingBox.X2 += PCB->Bloat; Text->BoundingBox.Y2 += PCB->Bloat; close_box(&Text->BoundingBox); } /*! * \brief Returns true if data area is empty. */ bool IsDataEmpty (DataType *Data) { bool hasNoObjects; Cardinal i; hasNoObjects = (Data->ViaN == 0); hasNoObjects &= (Data->ElementN == 0); for (i = 0; i < max_copper_layer + SILK_LAYER; i++) hasNoObjects = hasNoObjects && Data->Layer[i].LineN == 0 && Data->Layer[i].ArcN == 0 && Data->Layer[i].TextN == 0 && Data->Layer[i].PolygonN == 0; return (hasNoObjects); } int FlagIsDataEmpty (int parm) { int i = IsDataEmpty (PCB->Data); return parm ? !i : i; } /* FLAG(DataEmpty,FlagIsDataEmpty,0) */ /* FLAG(DataNonEmpty,FlagIsDataEmpty,1) */ bool IsLayerEmpty (LayerType *layer) { return (layer->LineN == 0 && layer->TextN == 0 && layer->PolygonN == 0 && layer->ArcN == 0); } bool IsLayerNumEmpty (int num) { return IsLayerEmpty (PCB->Data->Layer+num); } bool IsLayerGroupEmpty (int num) { int i; for (i=0; iLayerGroups.Number[num]; i++) if (!IsLayerNumEmpty (PCB->LayerGroups.Entries[num][i])) return false; return true; } bool IsPasteEmpty (int side) { bool paste_empty = true; ALLPAD_LOOP (PCB->Data); { if (ON_SIDE (pad, side) && !TEST_FLAG (NOPASTEFLAG, pad) && pad->Mask > 0) { paste_empty = false; break; } } ENDALL_LOOP; return paste_empty; } typedef struct { int nplated; int nunplated; Cardinal group_from; Cardinal group_to; } HoleCountStruct; static int hole_counting_callback (const BoxType * b, void *cl) { PinType *pin = (PinType *) b; HoleCountStruct *hcs = (HoleCountStruct *) cl; if (hcs->group_from != 0 || hcs->group_to != 0) { if (VIA_IS_BURIED (pin)) { if (hcs->group_from == GetLayerGroupNumberByNumber (pin->BuriedFrom) && hcs->group_to == GetLayerGroupNumberByNumber (pin->BuriedTo)) goto count; } return 1; } count: if (TEST_FLAG (HOLEFLAG, pin)) hcs->nunplated++; else hcs->nplated++; return 1; } /*! * \brief Counts the number of plated and unplated holes in the design * within a given area of the board. * * To count for the whole board, pass NULL to the within_area. */ void CountHoles (int *plated, int *unplated, const BoxType *within_area) { HoleCountStruct hcs = {0, 0, 0, 0}; r_search (PCB->Data->pin_tree, within_area, NULL, hole_counting_callback, &hcs); r_search (PCB->Data->via_tree, within_area, NULL, hole_counting_callback, &hcs); if (plated != NULL) *plated = hcs.nplated; if (unplated != NULL) *unplated = hcs.nunplated; } /*! * \brief Counts the number of plated and unplated holes in the design * within a given area of the board. * * To count for the whole board, pass NULL to the within_area. */ void CountHolesEx (int *plated, int *unplated, const BoxType *within_area, Cardinal group_from, Cardinal group_to) { HoleCountStruct hcs = {0, 0, group_from, group_to}; r_search (PCB->Data->pin_tree, within_area, NULL, hole_counting_callback, &hcs); r_search (PCB->Data->via_tree, within_area, NULL, hole_counting_callback, &hcs); if (plated != NULL) *plated = hcs.nplated; if (unplated != NULL) *unplated = hcs.nunplated; } /*! * \brief Gets minimum and maximum coordinates. * * \return NULL if layout is empty. */ BoxType * GetDataBoundingBox (DataType *Data) { static BoxType box; /* FIX ME: use r_search to do this much faster */ /* preset identifiers with highest and lowest possible values */ box.X1 = box.Y1 = MAX_COORD; box.X2 = box.Y2 = -MAX_COORD; /* now scan for the lowest/highest X and Y coordinate */ VIA_LOOP (Data); { box.X1 = MIN (box.X1, via->X - via->Thickness / 2); box.Y1 = MIN (box.Y1, via->Y - via->Thickness / 2); box.X2 = MAX (box.X2, via->X + via->Thickness / 2); box.Y2 = MAX (box.Y2, via->Y + via->Thickness / 2); } END_LOOP; ELEMENT_LOOP (Data); { box.X1 = MIN (box.X1, element->BoundingBox.X1); box.Y1 = MIN (box.Y1, element->BoundingBox.Y1); box.X2 = MAX (box.X2, element->BoundingBox.X2); box.Y2 = MAX (box.Y2, element->BoundingBox.Y2); { TextType *text = &NAMEONPCB_TEXT (element); box.X1 = MIN (box.X1, text->BoundingBox.X1); box.Y1 = MIN (box.Y1, text->BoundingBox.Y1); box.X2 = MAX (box.X2, text->BoundingBox.X2); box.Y2 = MAX (box.Y2, text->BoundingBox.Y2); }; } END_LOOP; ALLLINE_LOOP (Data); { box.X1 = MIN (box.X1, line->Point1.X - line->Thickness / 2); box.Y1 = MIN (box.Y1, line->Point1.Y - line->Thickness / 2); box.X1 = MIN (box.X1, line->Point2.X - line->Thickness / 2); box.Y1 = MIN (box.Y1, line->Point2.Y - line->Thickness / 2); box.X2 = MAX (box.X2, line->Point1.X + line->Thickness / 2); box.Y2 = MAX (box.Y2, line->Point1.Y + line->Thickness / 2); box.X2 = MAX (box.X2, line->Point2.X + line->Thickness / 2); box.Y2 = MAX (box.Y2, line->Point2.Y + line->Thickness / 2); } ENDALL_LOOP; ALLARC_LOOP (Data); { box.X1 = MIN (box.X1, arc->BoundingBox.X1); box.Y1 = MIN (box.Y1, arc->BoundingBox.Y1); box.X2 = MAX (box.X2, arc->BoundingBox.X2); box.Y2 = MAX (box.Y2, arc->BoundingBox.Y2); } ENDALL_LOOP; ALLTEXT_LOOP (Data); { box.X1 = MIN (box.X1, text->BoundingBox.X1); box.Y1 = MIN (box.Y1, text->BoundingBox.Y1); box.X2 = MAX (box.X2, text->BoundingBox.X2); box.Y2 = MAX (box.Y2, text->BoundingBox.Y2); } ENDALL_LOOP; ALLPOLYGON_LOOP (Data); { box.X1 = MIN (box.X1, polygon->BoundingBox.X1); box.Y1 = MIN (box.Y1, polygon->BoundingBox.Y1); box.X2 = MAX (box.X2, polygon->BoundingBox.X2); box.Y2 = MAX (box.Y2, polygon->BoundingBox.Y2); } ENDALL_LOOP; return (IsDataEmpty (Data) ? NULL : &box); } /*! * \brief Centers the displayed PCB around the specified point (X,Y), * and move the crosshair there. * * If warp_pointer is true warp the pointer to the crosshair. */ void CenterDisplay (Coord X, Coord Y, bool warp_pointer) { Coord save_grid = PCB->Grid; PCB->Grid = 1; if (MoveCrosshairAbsolute (X, Y)) notify_crosshair_change (true); if (warp_pointer) gui->set_crosshair (Crosshair.X, Crosshair.Y, HID_SC_CENTER_IN_VIEWPORT_AND_WARP_POINTER ); else gui->set_crosshair (Crosshair.X, Crosshair.Y, HID_SC_CENTER_IN_VIEWPORT); PCB->Grid = save_grid; } /*! * \brief Transforms symbol coordinates so that the left edge of each * symbol is at the zero position. * * The y coordinates are moved so that min(y) = 0. * */ void SetFontInfo (FontType *Ptr) { Cardinal i, j; SymbolType *symbol; LineType *line; Coord totalminy = MAX_COORD; /* calculate cell with and height (is at least DEFAULT_CELLSIZE) * maximum cell width and height * minimum x and y position of all lines */ Ptr->MaxWidth = DEFAULT_CELLSIZE; Ptr->MaxHeight = DEFAULT_CELLSIZE; for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++) { Coord minx, miny, maxx, maxy; /* next one if the index isn't used or symbol is empty (SPACE) */ if (!symbol->Valid || !symbol->LineN) continue; minx = miny = MAX_COORD; maxx = maxy = 0; for (line = symbol->Line, j = symbol->LineN; j; j--, line++) { minx = MIN (minx, line->Point1.X); miny = MIN (miny, line->Point1.Y); minx = MIN (minx, line->Point2.X); miny = MIN (miny, line->Point2.Y); maxx = MAX (maxx, line->Point1.X); maxy = MAX (maxy, line->Point1.Y); maxx = MAX (maxx, line->Point2.X); maxy = MAX (maxy, line->Point2.Y); } /* move symbol to left edge */ for (line = symbol->Line, j = symbol->LineN; j; j--, line++) MOVE_LINE_LOWLEVEL (line, -minx, 0); /* set symbol bounding box with a minimum cell size of (1,1) */ symbol->Width = maxx - minx + 1; symbol->Height = maxy + 1; /* check total min/max */ Ptr->MaxWidth = MAX (Ptr->MaxWidth, symbol->Width); Ptr->MaxHeight = MAX (Ptr->MaxHeight, symbol->Height); totalminy = MIN (totalminy, miny); } /* move coordinate system to the upper edge (lowest y on screen) */ for (i = 0, symbol = Ptr->Symbol; i <= MAX_FONTPOSITION; i++, symbol++) if (symbol->Valid) { symbol->Height -= totalminy; for (line = symbol->Line, j = symbol->LineN; j; j--, line++) MOVE_LINE_LOWLEVEL (line, 0, -totalminy); } /* setup the box for the default symbol */ Ptr->DefaultSymbol.X1 = Ptr->DefaultSymbol.Y1 = 0; Ptr->DefaultSymbol.X2 = Ptr->DefaultSymbol.X1 + Ptr->MaxWidth; Ptr->DefaultSymbol.Y2 = Ptr->DefaultSymbol.Y1 + Ptr->MaxHeight; } static Coord GetNum (char **s, const char *default_unit) { /* Read value */ Coord ret_val = GetValueEx (*s, NULL, NULL, NULL, default_unit); /* Advance pointer */ while(isalnum(**s) || **s == '.') (*s)++; return ret_val; } /*! * \brief Serializes the route style list . * * Right now n_styles should always be set to NUM_STYLES, * since that is the number of route styles ParseRouteString() * expects to parse. */ char * make_route_string (RouteStyleType rs[], int n_styles) { GString *str = g_string_new (""); gint i; for (i = 0; i < n_styles; ++i) { char *r_string; // don't much like how this is done, but it'll have to do for now if (rs[i].ViaMask != 0) r_string = pcb_g_strdup_printf ("%s,%$mr,%$mr,%$mr,%$mr,%$mr", rs[i].Name, rs[i].Thick, rs[i].Diameter, rs[i].Hole, rs[i].Keepaway, rs[i].ViaMask); else r_string = pcb_g_strdup_printf ("%s,%$mr,%$mr,%$mr,%$mr", rs[i].Name, rs[i].Thick, rs[i].Diameter, rs[i].Hole, rs[i].Keepaway); if (i > 0) g_string_append_c (str, ':'); g_string_append (str, r_string); g_free (r_string); } return g_string_free (str, FALSE); } /*! * \brief Parses the routes definition string * * Which is a colon separated list of comma separated Name, Dimension, * Dimension, Dimension[, Dimension, Dimension]. * * \example Signal,20,40,20,10,0:Power,40,60,28,10,0:... */ int ParseRouteString (char *s, RouteStyleType *routeStyle, const char *default_unit) { int i, n, style; char Name[256]; char *orig_s = s; Coord *style_items[5]; style = 0; while (style < NUM_STYLES) { // Clear any existing data memset (routeStyle, 0, sizeof (RouteStyleType)); // Extract the name while (*s && isspace ((int) *s)) s++; // this will break for style names greater than 256 characters for (i = 0; *s && *s != ','; i++) Name[i] = *s++; Name[i] = '\0'; routeStyle->Name = strdup (Name); // setup some default values routeStyle->Keepaway = MIL_TO_COORD(10); routeStyle->ViaMask = 0; // Now extract the numerical parameters style_items[0] = &(routeStyle->Thick); style_items[1] = &(routeStyle->Diameter); style_items[2] = &(routeStyle->Hole); style_items[3] = &(routeStyle->Keepaway); style_items[4] = &(routeStyle->ViaMask); for (n = 0; n < 5; n++) { if (!isdigit ((int) *++s)) goto error; *style_items[n] = GetNum(&s, default_unit); // find the next field, skipping any white space while (*s && isspace ((int) *s)) s++; if (*s != ',') break; while (*s && isspace ((int) *s)) s++; } // how did we get out of the loop? // if we're at the end of the string, we're done if (*s == '\0') break; // there's another route style to parse, advance past the delimiter else if (*s == ':') s++; // otherwise, we got an unexpected character, which is an error else { fprintf(stderr, "unexpected character: %c\n", *s); goto error; } // otherwise, prepare for the next loop style++; routeStyle++; } return (0); error: fprintf(stderr, "error parsing route string: %s\n", orig_s); fprintf(stderr, "parsed %d characters.\n", (int) (s - orig_s)); fprintf(stderr, "on style number %d\n", style+1); fprintf(stderr, "character that caused the error: %c\n", *s); fprintf(stderr, "values of current struct: \n"); for (n=0; n < 5; n++) fprintf(stderr, "%d: %lld ", n, (long long int) *style_items[n]); memset (routeStyle, 0, NUM_STYLES * sizeof (RouteStyleType)); return (1); } /*! * \brief Parses the group definition string. * * Which is a colon separated list of comma separated layer numbers. * * \example (1,2,b:4,6,8,t) */ int ParseGroupString (char *group_string, LayerGroupType *LayerGroup, int *LayerN) { char *s; int group, member, layer; bool c_set = false, /* flags for the two special layers to */ s_set = false; /* provide a default setting for old formats */ int groupnum[MAX_ALL_LAYER]; *LayerN = 0; /* Deterimine the maximum layer number */ for (s = group_string; s && *s; s++) { while (*s && isspace ((int) *s)) s++; switch (*s) { case 'c': case 'C': case 't': case 'T': case 's': case 'S': case 'b': case 'B': break; default: if (!isdigit ((int) *s)) goto error; *LayerN = MAX (*LayerN, atoi (s)); break; } while (*++s && isdigit ((int) *s)); /* ignore white spaces and check for separator */ while (*s && isspace ((int) *s)) s++; if (*s == '\0') break; if (*s != ':' && *s != ',') goto error; } /* clear struct */ memset (LayerGroup, 0, sizeof (LayerGroupType)); /* Clear assignments */ for (layer = 0; layer < MAX_ALL_LAYER; layer++) groupnum[layer] = -1; /* loop over all groups */ for (s = group_string, group = 0; s && *s && group < *LayerN; group++) { while (*s && isspace ((int) *s)) s++; /* loop over all group members */ for (member = 0; *s; s++) { /* ignore white spaces and get layernumber */ while (*s && isspace ((int) *s)) s++; switch (*s) { case 'c': case 'C': case 't': case 'T': layer = *LayerN + TOP_SILK_LAYER; c_set = true; break; case 's': case 'S': case 'b': case 'B': layer = *LayerN + BOTTOM_SILK_LAYER; s_set = true; break; default: layer = atoi (s) - 1; break; } if (layer > *LayerN + MAX (BOTTOM_SILK_LAYER, TOP_SILK_LAYER) || member >= *LayerN + 1) goto error; groupnum[layer] = group; LayerGroup->Entries[group][member++] = layer; while (*++s && isdigit ((int) *s)); /* ignore white spaces and check for separator */ while (*s && isspace ((int) *s)) s++; if (!*s || *s == ':') break; } LayerGroup->Number[group] = member; if (*s == ':') s++; } /* If no explicit solder or component layer group was found in the layer * group string, make group 0 the bottom side, and group 1 the top side. * This is done by assigning the relevant silkscreen layers to those groups. */ if (!s_set) LayerGroup->Entries[0][LayerGroup->Number[0]++] = *LayerN + BOTTOM_SILK_LAYER; if (!c_set) LayerGroup->Entries[1][LayerGroup->Number[1]++] = *LayerN + TOP_SILK_LAYER; /* Assign a unique layer group to each layer that was not explicitly * assigned a particular group by its presence in the layer group string. */ for (layer = 0; layer < *LayerN && group < *LayerN; layer++) if (groupnum[layer] == -1) { LayerGroup->Entries[group][0] = layer; LayerGroup->Number[group] = 1; group++; } return (0); /* reset structure on error */ error: memset (LayerGroup, 0, sizeof (LayerGroupType)); return (1); } /*! * \brief Sets up any remaining layer type guesses. */ void AssignDefaultLayerTypes() { int num_found; Cardinal outline_layer = -1; /* * There can be only one outline layer. During parsing guess_layertype() * applied well known cases already, but as this function operates on a * single layer only, it might end up with more than one hit for the whole * file. Especially after loading an older layout without saved flags. */ num_found = 0; LAYER_TYPE_LOOP (PCB->Data, max_copper_layer, LT_OUTLINE) outline_layer = n; num_found++; END_LOOP; if (num_found != 1) /* No or duplicate outline! Try to find a layer which is named exactly "outline". */ LAYER_TYPE_LOOP (PCB->Data, max_copper_layer, LT_OUTLINE) if ( ! strcasecmp (layer->Name, "outline")) { outline_layer = n; num_found = 1; break; } END_LOOP; if (num_found != 1) /* Next, try to find a layer which is named exactly "route". */ LAYER_TYPE_LOOP (PCB->Data, max_copper_layer, LT_OUTLINE) if ( ! strcasecmp (layer->Name, "route")) { outline_layer = n; num_found = 1; break; } END_LOOP; if (num_found != 1) /* As last resort, take the first layer claiming to be outline. */ LAYER_TYPE_LOOP (PCB->Data, max_copper_layer, LT_OUTLINE) outline_layer = n; num_found = 1; break; END_LOOP; /* Make sure our found outline layer is the only one. */ LAYER_TYPE_LOOP (PCB->Data, max_copper_layer, LT_OUTLINE) if (n == outline_layer) layer->Type = LT_OUTLINE; else layer->Type = LT_ROUTE; /* best guess */ END_LOOP; } extern void pcb_main_uninit(void); /*! * \brief Quits application. */ void QuitApplication (void) { /* * save data if necessary. It not needed, then don't trigger EmergencySave * via our atexit() registering of EmergencySave(). We presumeably wanted to * exit here and thus it is not an emergency. */ if (PCB->Changed && Settings.SaveInTMP) EmergencySave (); else DisableEmergencySave (); if (gui->do_exit == NULL) { pcb_main_uninit (); exit (0); } else gui->do_exit (gui); } /*! * \brief Creates a filename from a template. * * "%f" is replaced by the filename. * * "%p" is replaced by the searchpath. */ char * EvaluateFilename (char *Template, char *Path, char *Filename, char *Parameter) { static DynamicStringType command; char *p; if (Settings.verbose) { printf ("EvaluateFilename:\n"); printf ("\tTemplate: \033[33m%s\033[0m\n", Template); printf ("\tPath: \033[33m%s\033[0m\n", Path); printf ("\tFilename: \033[33m%s\033[0m\n", Filename); printf ("\tParameter: \033[33m%s\033[0m\n", Parameter); } DSClearString (&command); for (p = Template; p && *p; p++) { /* copy character or add string to command */ if (*p == '%' && (*(p + 1) == 'f' || *(p + 1) == 'p' || *(p + 1) == 'a')) switch (*(++p)) { case 'a': DSAddString (&command, Parameter); break; case 'f': DSAddString (&command, Filename); break; case 'p': DSAddString (&command, Path); break; } else DSAddCharacter (&command, *p); } DSAddCharacter (&command, '\0'); if (Settings.verbose) printf ("EvaluateFilename: \033[32m%s\033[0m\n", command.Data); return strdup (command.Data); } /*! * \brief Concatenates directory and filename. * * If directory != NULL expands them with a shell and returns the found * name(s) or NULL. */ char * ExpandFilename (char *Dirname, char *Filename) { static DynamicStringType answer; char *command; FILE *pipe; int c; /* allocate memory for commandline and build it */ DSClearString (&answer); if (Dirname) { command = (char *)calloc (strlen (Filename) + strlen (Dirname) + 7, sizeof (char)); sprintf (command, "echo %s/%s", Dirname, Filename); } else { command = (char *)calloc (strlen (Filename) + 6, sizeof (char)); sprintf (command, "echo %s", Filename); } /* execute it with shell */ if ((pipe = popen (command, "r")) != NULL) { /* discard all but the first returned line */ for (;;) { if ((c = fgetc (pipe)) == EOF || c == '\n' || c == '\r') break; else DSAddCharacter (&answer, c); } free (command); return (pclose (pipe) ? NULL : answer.Data); } /* couldn't be expanded by the shell */ PopenErrorMessage (command); free (command); return (NULL); } /*! * \brief Returns the layer number for the passed pointer. */ int GetLayerNumber (DataType *Data, LayerType *Layer) { int i; for (i = 0; i < MAX_ALL_LAYER; i++) if (Layer == &Data->Layer[i]) break; return (i); } /*! * \brief Move layer (number is passed in) to top of layerstack. */ static void PushOnTopOfLayerStack (int NewTop) { int i; /* ignore silk and other extra layers */ if (NewTop < max_copper_layer) { /* first find position of passed one */ for (i = 0; i < max_copper_layer; i++) if (LayerStack[i] == NewTop) break; /* bring this element to the top of the stack */ for (; i; i--) LayerStack[i] = LayerStack[i - 1]; LayerStack[0] = NewTop; } } /*! * \brief Changes the visibility of all layers in a group. * * \return The number of changed layers. */ int ChangeGroupVisibility (int Layer, bool On, bool ChangeStackOrder) { int group, i, changed = 1; /* at least the current layer changes */ /* Warning: these special case values must agree with what gui-top-window.c | thinks the are. */ if (Settings.verbose) printf ("ChangeGroupVisibility(Layer=%d, On=%d, ChangeStackOrder=%d)\n", Layer, On, ChangeStackOrder); /* decrement 'i' to keep stack in order of layergroup */ group = GetLayerGroupNumberByNumber (Layer); for (i = PCB->LayerGroups.Number[group]; i;) { int layer = PCB->LayerGroups.Entries[group][--i]; /* don't count the passed member of the group */ if (layer != Layer && layer < max_copper_layer) { PCB->Data->Layer[layer].On = On; /* push layer on top of stack if switched on */ if (On && ChangeStackOrder) PushOnTopOfLayerStack (layer); changed++; } } /* change at least the passed layer */ PCB->Data->Layer[Layer].On = On; if (On && ChangeStackOrder) PushOnTopOfLayerStack (Layer); /* update control panel and exit */ hid_action ("LayersChanged"); return (changed); } /*! * \brief Given a string description of a layer stack, adjust the layer * stack to correspond. */ void LayerStringToLayerStack (char *s) { static int listed_layers = 0; int l = strlen (s); char **args; int i, argn, lno; int prev_sep = 1; s = strdup (s); args = (char **) malloc (l * sizeof (char *)); argn = 0; for (i=0; iData->Layer[i].On = false; } PCB->ElementOn = false; PCB->InvisibleObjectsOn = false; PCB->PinOn = false; PCB->ViaOn = false; PCB->RatOn = false; CLEAR_FLAG (SHOWMASKFLAG, PCB); Settings.ShowBottomSide = 0; for (i=argn-1; i>=0; i--) { if (strcasecmp (args[i], "rats") == 0) PCB->RatOn = true; else if (strcasecmp (args[i], "invisible") == 0) PCB->InvisibleObjectsOn = true; else if (strcasecmp (args[i], "pins") == 0) PCB->PinOn = true; else if (strcasecmp (args[i], "vias") == 0) PCB->ViaOn = true; else if (strcasecmp (args[i], "elements") == 0 || strcasecmp (args[i], "silk") == 0) PCB->ElementOn = true; else if (strcasecmp (args[i], "mask") == 0) SET_FLAG (SHOWMASKFLAG, PCB); else if (strcasecmp (args[i], "solderside") == 0) Settings.ShowBottomSide = 1; else if (isdigit ((int) args[i][0])) { lno = atoi (args[i]); ChangeGroupVisibility (lno, true, true); } else { int found = 0; for (lno = 0; lno < max_copper_layer; lno++) if (strcasecmp (args[i], PCB->Data->Layer[lno].Name) == 0) { ChangeGroupVisibility (lno, true, true); found = 1; break; } if (!found) { fprintf(stderr, _("Warning: layer \"%s\" not known\n"), args[i]); if (!listed_layers) { fprintf (stderr, _("Named layers in this board are:\n")); listed_layers = 1; for (lno=0; lno < max_copper_layer; lno ++) fprintf(stderr, "\t%s\n", PCB->Data->Layer[lno].Name); fprintf(stderr, _("Also: component, solder, rats, invisible, " "pins, vias, elements or silk, mask, solderside.\n")); } } } } } /*! * \brief Returns the layergroup number for the passed pointer. */ int GetLayerGroupNumberByPointer (LayerType *Layer) { return (GetLayerGroupNumberByNumber (GetLayerNumber (PCB->Data, Layer))); } /*! * \brief Returns the layergroup number for the passed layer number. */ int GetLayerGroupNumberByNumber (Cardinal Layer) { int group, entry; for (group = 0; group < max_group; group++) for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) if (PCB->LayerGroups.Entries[group][entry] == Layer) return (group); /* since every layer belongs to a group it is safe to return * the value without boundary checking */ return (group); } /*! * \brief Returns the layergroup number for the passed side (TOP_SIDE or * BOTTOM_SIDE). */ int GetLayerGroupNumberBySide (int side) { /* Find the relavant board side layer group by determining the * layer group associated with the relevant side's silk-screen */ return GetLayerGroupNumberByNumber ( side == TOP_SIDE ? top_silk_layer : bottom_silk_layer); } /*! * \brief Returns a pointer to an objects bounding box. * * Data is valid until the routine is called again. */ BoxType * GetObjectBoundingBox (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { switch (Type) { case LINE_TYPE: case ARC_TYPE: case TEXT_TYPE: case POLYGON_TYPE: case PAD_TYPE: case PIN_TYPE: case ELEMENTNAME_TYPE: return (BoxType *)Ptr2; case VIA_TYPE: case ELEMENT_TYPE: return (BoxType *)Ptr1; case POLYGONPOINT_TYPE: case LINEPOINT_TYPE: return (BoxType *)Ptr3; default: Message (_("Request for bounding box of unsupported type %d\n"), Type); return (BoxType *)Ptr2; } } /*! * \brief Computes the bounding box of an arc. */ void SetArcBoundingBox (ArcType *Arc) { double ca1, ca2, sa1, sa2; double minx, maxx, miny, maxy; Angle ang1, ang2; Coord width; /* first put angles into standard form: * ang1 < ang2, both angles between 0 and 720 */ Arc->Delta = CLAMP (Arc->Delta, -360, 360); if (Arc->Delta > 0) { ang1 = NormalizeAngle (Arc->StartAngle); ang2 = NormalizeAngle (Arc->StartAngle + Arc->Delta); } else { ang1 = NormalizeAngle (Arc->StartAngle + Arc->Delta); ang2 = NormalizeAngle (Arc->StartAngle); } if (ang1 > ang2) ang2 += 360; /* Make sure full circles aren't treated as zero-length arcs */ if (Arc->Delta == 360 || Arc->Delta == -360) ang2 = ang1 + 360; /* calculate sines, cosines */ sa1 = sin (M180 * ang1); ca1 = cos (M180 * ang1); sa2 = sin (M180 * ang2); ca2 = cos (M180 * ang2); minx = MIN (ca1, ca2); maxx = MAX (ca1, ca2); miny = MIN (sa1, sa2); maxy = MAX (sa1, sa2); /* Check for extreme angles */ if ((ang1 <= 0 && ang2 >= 0) || (ang1 <= 360 && ang2 >= 360)) maxx = 1; if ((ang1 <= 90 && ang2 >= 90) || (ang1 <= 450 && ang2 >= 450)) maxy = 1; if ((ang1 <= 180 && ang2 >= 180) || (ang1 <= 540 && ang2 >= 540)) minx = -1; if ((ang1 <= 270 && ang2 >= 270) || (ang1 <= 630 && ang2 >= 630)) miny = -1; /* Finally, calcate bounds, converting sane geometry into pcb geometry */ Arc->BoundingBox.X1 = Arc->X - Arc->Width * maxx; Arc->BoundingBox.X2 = Arc->X - Arc->Width * minx; Arc->BoundingBox.Y1 = Arc->Y + Arc->Height * miny; Arc->BoundingBox.Y2 = Arc->Y + Arc->Height * maxy; width = (Arc->Thickness + Arc->Clearance) / 2; /* Adjust for our discrete polygon approximation */ width = (double)width * MAX (POLY_CIRC_RADIUS_ADJ, (1.0 + POLY_ARC_MAX_DEVIATION)) + 0.5; Arc->BoundingBox.X1 -= width; Arc->BoundingBox.X2 += width; Arc->BoundingBox.Y1 -= width; Arc->BoundingBox.Y2 += width; close_box(&Arc->BoundingBox); /* Update the arc end-points */ Arc->Point1.X = Arc->X - (double)Arc->Width * ca1; Arc->Point1.Y = Arc->Y + (double)Arc->Height * sa1; Arc->Point2.X = Arc->X - (double)Arc->Width * ca2; Arc->Point2.Y = Arc->Y + (double)Arc->Height * sa2; } /*! * \brief Resets the layerstack setting. */ void ResetStackAndVisibility (void) { int top_group; Cardinal i; for (i = 0; i < max_copper_layer + SILK_LAYER; i++) { if (i < max_copper_layer) LayerStack[i] = i; PCB->Data->Layer[i].On = true; } PCB->ElementOn = true; PCB->InvisibleObjectsOn = true; PCB->PinOn = true; PCB->ViaOn = true; PCB->RatOn = true; /* Bring the component group to the front and make it active. */ top_group = GetLayerGroupNumberBySide (TOP_SIDE); ChangeGroupVisibility (PCB->LayerGroups.Entries[top_group][0], 1, 1); } /*! * \brief Saves the layerstack setting. */ void SaveStackAndVisibility (void) { Cardinal i; static bool run = false; if (run == false) { SavedStack.cnt = 0; run = true; } if (SavedStack.cnt != 0) { fprintf (stderr, "SaveStackAndVisibility() layerstack was already saved and not" "yet restored. cnt = %d\n", SavedStack.cnt); } for (i = 0; i < max_copper_layer + SILK_LAYER; i++) { if (i < max_copper_layer) SavedStack.LayerStack[i] = LayerStack[i]; SavedStack.LayerOn[i] = PCB->Data->Layer[i].On; } SavedStack.ElementOn = PCB->ElementOn; SavedStack.InvisibleObjectsOn = PCB->InvisibleObjectsOn; SavedStack.PinOn = PCB->PinOn; SavedStack.ViaOn = PCB->ViaOn; SavedStack.RatOn = PCB->RatOn; SavedStack.cnt++; } /*! * \brief Restores the layerstack setting. */ void RestoreStackAndVisibility (void) { Cardinal i; if (SavedStack.cnt == 0) { fprintf (stderr, "RestoreStackAndVisibility() layerstack has not" " been saved. cnt = %d\n", SavedStack.cnt); return; } else if (SavedStack.cnt != 1) { fprintf (stderr, "RestoreStackAndVisibility() layerstack save count is" " wrong. cnt = %d\n", SavedStack.cnt); } for (i = 0; i < max_copper_layer + SILK_LAYER; i++) { if (i < max_copper_layer) LayerStack[i] = SavedStack.LayerStack[i]; PCB->Data->Layer[i].On = SavedStack.LayerOn[i]; } PCB->ElementOn = SavedStack.ElementOn; PCB->InvisibleObjectsOn = SavedStack.InvisibleObjectsOn; PCB->PinOn = SavedStack.PinOn; PCB->ViaOn = SavedStack.ViaOn; PCB->RatOn = SavedStack.RatOn; SavedStack.cnt--; } /*! * \brief Returns pointer to current working directory. * * If 'path' is not NULL, then the current working directory is copied * to the array pointed to by 'path'. */ char * GetWorkingDirectory (char *path) { #ifdef HAVE_GETCWD return getcwd (path, MAXPATHLEN); #else /* seems that some BSD releases lack of a prototype for getwd() */ return getwd (path); #endif } /*! * \brief Write a string to the passed file pointer. * * Some special characters are quoted. */ void CreateQuotedString (DynamicStringType *DS, char *S) { DSClearString (DS); DSAddCharacter (DS, '"'); while (*S) { if (*S == '"' || *S == '\\') DSAddCharacter (DS, '\\'); DSAddCharacter (DS, *S++); } DSAddCharacter (DS, '"'); } BoxType * GetArcEnds (ArcType *Arc) { static BoxType box; box.X1 = Arc->X - Arc->Width * cos (Arc->StartAngle * M180); box.Y1 = Arc->Y + Arc->Height * sin (Arc->StartAngle * M180); box.X2 = Arc->X - Arc->Width * cos ((Arc->StartAngle + Arc->Delta) * M180); box.Y2 = Arc->Y + Arc->Height * sin ((Arc->StartAngle + Arc->Delta) * M180); return &box; } /*! * \todo Doesn't this belong in change.c ?? */ void ChangeArcAngles (LayerType *Layer, ArcType *a, Angle new_sa, Angle new_da) { if (new_da >= 360) { new_da = 360; new_sa = 0; } RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, a); r_delete_entry (Layer->arc_tree, (BoxType *) a); AddObjectToChangeAnglesUndoList (ARC_TYPE, a, a, a); a->StartAngle = new_sa; a->Delta = new_da; SetArcBoundingBox (a); r_insert_entry (Layer->arc_tree, (BoxType *) a, 0); ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, a); } static char * BumpName (char *Name) { int num; char c, *start; static char temp[256]; start = Name; /* seek end of string */ while (*Name != 0) Name++; /* back up to potential number */ for (Name--; isdigit ((int) *Name); Name--); Name++; if (*Name) num = atoi (Name) + 1; else num = 1; c = *Name; *Name = 0; sprintf (temp, "%s%d", start, num); /* if this is not our string, put back the blown character */ if (start != temp) *Name = c; return (temp); } /*! * \brief Make a unique name for the name on board. * * This can alter the contents of the input string. */ char * UniqueElementName (DataType *Data, char *Name) { bool unique = true; /* null strings are ok */ if (!Name || !*Name) return (Name); for (;;) { ELEMENT_LOOP (Data); { if (NAMEONPCB_NAME (element) && NSTRCMP (NAMEONPCB_NAME (element), Name) == 0) { Name = BumpName (Name); unique = false; break; } } END_LOOP; if (unique) return (Name); unique = true; } } static void GetGridLockCoordinates (int type, void *ptr1, void *ptr2, void *ptr3, Coord * x, Coord * y) { switch (type) { case VIA_TYPE: *x = ((PinType *) ptr2)->X; *y = ((PinType *) ptr2)->Y; break; case LINE_TYPE: *x = ((LineType *) ptr2)->Point1.X; *y = ((LineType *) ptr2)->Point1.Y; break; case TEXT_TYPE: case ELEMENTNAME_TYPE: *x = ((TextType *) ptr2)->X; *y = ((TextType *) ptr2)->Y; break; case ELEMENT_TYPE: *x = ((ElementType *) ptr2)->MarkX; *y = ((ElementType *) ptr2)->MarkY; break; case POLYGON_TYPE: *x = ((PolygonType *) ptr2)->Points[0].X; *y = ((PolygonType *) ptr2)->Points[0].Y; break; case LINEPOINT_TYPE: case POLYGONPOINT_TYPE: *x = ((PointType *) ptr3)->X; *y = ((PointType *) ptr3)->Y; break; case ARC_TYPE: { BoxType *box; box = GetArcEnds ((ArcType *) ptr2); *x = box->X1; *y = box->Y1; break; } } } void AttachForCopy (Coord PlaceX, Coord PlaceY) { Coord mx = 0, my = 0; Crosshair.AttachedObject.RubberbandN = 0; if (! TEST_FLAG (SNAPPINFLAG, PCB)) { /* dither the grab point so that the mark, center, etc * will end up on a grid coordinate */ GetGridLockCoordinates (Crosshair.AttachedObject.Type, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, Crosshair.AttachedObject.Ptr3, &mx, &my); mx = GridFit (mx, PCB->Grid, PCB->GridOffsetX) - mx; my = GridFit (my, PCB->Grid, PCB->GridOffsetY) - my; } Crosshair.AttachedObject.X = PlaceX - mx; Crosshair.AttachedObject.Y = PlaceY - my; if (!Marked.status || TEST_FLAG (LOCALREFFLAG, PCB)) SetLocalRef (PlaceX - mx, PlaceY - my, true); Crosshair.AttachedObject.State = STATE_SECOND; /* get boundingbox of object and set cursor range */ crosshair_update_range(); /* get all attached objects if necessary */ if ((Settings.Mode != COPY_MODE) && TEST_FLAG (RUBBERBANDFLAG, PCB)) LookupRubberbandLines (Crosshair.AttachedObject.Type, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, Crosshair.AttachedObject.Ptr3); if (Settings.Mode != COPY_MODE && (Crosshair.AttachedObject.Type == ELEMENT_TYPE || Crosshair.AttachedObject.Type == VIA_TYPE || Crosshair.AttachedObject.Type == LINE_TYPE || Crosshair.AttachedObject.Type == LINEPOINT_TYPE)) LookupRatLines (Crosshair.AttachedObject.Type, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, Crosshair.AttachedObject.Ptr3); } /*! * \brief Return nonzero if the given file exists and is readable. */ int FileExists (const char *name) { FILE *f; f = fopen (name, "r"); if (f) { fclose (f); return 1; } return 0; } char * Concat (const char *first, ...) { char *rv; int len; va_list a; len = strlen (first); rv = (char *) malloc (len + 1); strcpy (rv, first); va_start (a, first); while (1) { const char *s = va_arg (a, const char *); if (!s) break; len += strlen (s); rv = (char *) realloc (rv, len + 1); strcat (rv, s); } va_end (a); return rv; } /* Layer Group Functions. */ /*! * \brief Returns group actually moved to (i.e. either group or * previous). */ int MoveLayerToGroup (int layer, int group) { int prev, i, j; if (layer < 0 || layer > max_copper_layer + 1) return -1; prev = GetLayerGroupNumberByNumber (layer); if ((layer == bottom_silk_layer && group == GetLayerGroupNumberByNumber (top_silk_layer)) || (layer == top_silk_layer && group == GetLayerGroupNumberByNumber (bottom_silk_layer)) || (group < 0 || group >= max_group) || (prev == group)) return prev; /* Remove layer from prev group */ for (j = i = 0; i < PCB->LayerGroups.Number[prev]; i++) if (PCB->LayerGroups.Entries[prev][i] != layer) PCB->LayerGroups.Entries[prev][j++] = PCB->LayerGroups.Entries[prev][i]; PCB->LayerGroups.Number[prev]--; /* Add layer to new group. */ i = PCB->LayerGroups.Number[group]++; PCB->LayerGroups.Entries[group][i] = layer; return group; } /*! * \brief Returns pointer to private buffer. */ char * LayerGroupsToString (LayerGroupType *lg) { #if MAX_ALL_LAYER < 9999 /* Allows for layer numbers 0..9999 */ static char buf[(MAX_ALL_LAYER) * 5 + 1]; #endif char *cp = buf; char sep = 0; int group, entry; for (group = 0; group < max_group; group++) if (PCB->LayerGroups.Number[group]) { if (sep) *cp++ = ':'; sep = 1; for (entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) { int layer = PCB->LayerGroups.Entries[group][entry]; if (layer == top_silk_layer) { *cp++ = 'c'; } else if (layer == bottom_silk_layer) { *cp++ = 's'; } else { sprintf (cp, "%d", layer + 1); while (*++cp) ; } if (entry != PCB->LayerGroups.Number[group] - 1) *cp++ = ','; } } *cp++ = 0; return buf; } int GetMaxBottomLayer () { int l = 0; int group, i; group = GetLayerGroupNumberBySide (BOTTOM_SIDE); for (i = 0; i < PCB->LayerGroups.Number[group]; i++) { if (PCB->LayerGroups.Entries[group][i] < max_copper_layer) l = max (l, PCB->LayerGroups.Entries[group][i]); } return l; } /*! * \brief Sanitize buried via * * - remove degraded vias * - ensure correct order of layers * - change full size vias to TH vias */ void SanitizeBuriedVia (PinType *via) { /* we expect that via is burried/blind */ if (via->BuriedFrom > via->BuriedTo) { int tmp = via->BuriedFrom; via->BuriedFrom = via->BuriedTo; via->BuriedTo = tmp; } /* check, if via was extended to full stack (after first layer removal)*/ /* convert it in TH via in such case */ if (via->BuriedTo == GetMaxBottomLayer () && via->BuriedFrom == 0) via->BuriedTo = 0; } #if 0 bool IsLayerMoveSafe (int old_index, int new_index) { VIA_LOOP (PCB->Data); { if (VIA_IS_BURIED (via)) { /* moving from below to inside */ if ((old_index < via->BuriedFrom) && (new_index < via->BuriedTo)) return false; /* moving from above to inside */ if ((old_index > via->BuriedTo) && (new_index > via->BuriedFrom)) return false; } } END_LOOP; return true; } #endif /*! * \brief Update buried vias after layer move * */ void ChangeBuriedViasAfterLayerMove (int old_index, int new_index) { VIA_LOOP (PCB->Data); { if (VIA_IS_BURIED (via)) { /* do nothing, if both layers are below the via */ if ((old_index < via->BuriedFrom) && (new_index < via->BuriedFrom)) continue; /* do nothing, if both layers are above the via */ if ((old_index > via->BuriedTo) && (new_index > via->BuriedTo)) continue; /* moving via top layer - via top follows layer */ if (old_index == via->BuriedFrom) { AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedFrom = new_index; } /* moving via bottom layer - via bottom follows layer */ else if (old_index == via->BuriedTo) { AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedTo = new_index; } /* moving layer covered by via inside the via (except top and bottom) - do nothing */ else if (VIA_ON_LAYER (via, old_index) && VIA_ON_LAYER (via, new_index)) continue; /* moving from inside to below - shrink via DANGEROUS op*/ else if (VIA_ON_LAYER (via, old_index) && (new_index < via->BuriedFrom)) { AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedFrom++; } /* moving from inside to above - shrink via DANGEROUS op*/ else if (VIA_ON_LAYER (via, old_index) && (new_index > via->BuriedTo)) { AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedTo--; } /* moving from above to below - shift via up */ else if ((old_index > via->BuriedTo) && (new_index < via->BuriedFrom)) { AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedFrom++; via->BuriedTo++; } /* moving from below to above - shift via down */ else if ((old_index < via->BuriedFrom) && (new_index >= via->BuriedTo)) { AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedFrom--; via->BuriedTo--; } /* moving from below to inside - extend via down DANGEROUS op*/ else if ((old_index < via->BuriedFrom) && (new_index < via->BuriedTo)) { AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedFrom--; } /* moving from above to inside - extend via up DANGEROUS op*/ else if ((old_index > via->BuriedTo) && (new_index > via->BuriedFrom)) { AddObjectToSetViaLayersUndoList ( via, via, via); via->BuriedTo++; } else { Message (_("Layer move: failed via update: %d -> %d, via: %d:%d\n"), old_index, new_index, via->BuriedFrom, via->BuriedTo); continue; } SanitizeBuriedVia (via); } } END_LOOP; RemoveDegradedVias (); } /*! * \brief Update buried vias after new layer create * */ void ChangeBuriedViasAfterLayerCreate (int index) { VIA_LOOP (PCB->Data); { if (VIA_IS_BURIED (via)) { if (index <= via->BuriedFrom || index <= via->BuriedTo) AddObjectToSetViaLayersUndoList (via, via, via); if (index <= via->BuriedFrom) via->BuriedFrom++; if (index <= via->BuriedTo) via->BuriedTo++; } } END_LOOP; } /*! * \brief Update buried vias after layer delete * */ void ChangeBuriedViasAfterLayerDelete (int index) { VIA_LOOP (PCB->Data); { if (VIA_IS_BURIED (via)) { if (index < via->BuriedFrom || index <= via->BuriedTo) AddObjectToSetViaLayersUndoList (via, via, via); if (index < via->BuriedFrom) via->BuriedFrom--; if (index <= via->BuriedTo) via->BuriedTo--; SanitizeBuriedVia (via); } } END_LOOP; RemoveDegradedVias (); } /*! * \brief Check if via penetrates layer group * */ bool ViaIsOnLayerGroup (PinType *via, int group) { Cardinal layer; if (!VIA_IS_BURIED (via)) return true; for (layer = via->BuriedFrom; layer <= via->BuriedTo; layer++) { if (GetLayerGroupNumberByNumber (layer) == group) return true; } return false; } /*! * \brief Check if via penetrates any visible layer * */ bool ViaIsOnAnyVisibleLayer (PinType *via) { Cardinal layer; if (!VIA_IS_BURIED (via)) return true; for (layer = via->BuriedFrom; layer <= via->BuriedTo; layer ++) { if (PCB->Data->Layer[layer].On) return true; } return false; } char * pcb_author (void) { #ifdef HAVE_GETPWUID static struct passwd *pwentry; static char *fab_author = 0; if (!fab_author) { if (Settings.FabAuthor && Settings.FabAuthor[0]) fab_author = Settings.FabAuthor; else { int len; char *comma, *gecos; /* ID the user. */ pwentry = getpwuid (getuid ()); gecos = pwentry->pw_gecos; comma = strchr (gecos, ','); if (comma) len = comma - gecos; else len = strlen (gecos); fab_author = (char *)malloc (len + 1); if (!fab_author) { perror ("pcb: out of memory.\n"); exit (-1); } memcpy (fab_author, gecos, len); fab_author[len] = 0; } } return fab_author; #else return "Unknown"; #endif } /*! * \brief Returns NULL if the name isn't found, else the value for that * named attribute. */ char * AttributeGetFromList (AttributeListType *list, char *name) { int i; for (i=0; iNumber; i++) if (strcmp (name, list->List[i].name) == 0) return list->List[i].value; return NULL; } /*! * \brief Adds an attribute to the list. * * If the attribute already exists, whether it's replaced or a second * copy added depends on REPLACE. * * \return Non-zero if an existing attribute was replaced. */ int AttributePutToList (AttributeListType *list, const char *name, const char *value, int replace) { int i; /* If we're allowed to replace an existing attribute, see if we can. */ if (replace) { for (i=0; iNumber; i++) if (strcmp (name, list->List[i].name) == 0) { free (list->List[i].value); list->List[i].value = STRDUP (value); return 1; } } /* At this point, we're going to need to add a new attribute to the list. See if there's room. */ if (list->Number >= list->Max) { list->Max += 10; list->List = (AttributeType *) realloc (list->List, list->Max * sizeof (AttributeType)); } /* Now add the new attribute. */ i = list->Number; list->List[i].name = STRDUP (name); list->List[i].value = STRDUP (value); list->Number ++; return 0; } /*! * \brief Remove an attribute by name. */ void AttributeRemoveFromList(AttributeListType *list, char *name) { int i, j; for (i=0; iNumber; i++) if (strcmp (name, list->List[i].name) == 0) { free (list->List[i].name); free (list->List[i].value); for (j=i; jNumber-1; j++) list->List[j] = list->List[j+1]; list->Number --; } } /*! * \todo In future all use of this should be supplanted by pcb-printf * and %mr/%m# spec. * * These act like you'd expect, except always in the C locale. */ const char * c_dtostr (double d) { static char buf[100]; int i, f; char *bufp = buf; if (d < 0) { *bufp++ = '-'; d = -d; } d += 0.0000005; /* rounding */ i = floor (d); d -= i; sprintf (bufp, "%d", i); bufp += strlen (bufp); *bufp++ = '.'; f = floor (d * 1000000.0); sprintf (bufp, "%06d", f); return buf; } void r_delete_element (DataType * data, ElementType * element) { r_delete_entry (data->element_tree, (BoxType *) element); PIN_LOOP (element); { r_delete_entry (data->pin_tree, (BoxType *) pin); } END_LOOP; PAD_LOOP (element); { r_delete_entry (data->pad_tree, (BoxType *) pad); } END_LOOP; ELEMENTTEXT_LOOP (element); { r_delete_entry (data->name_tree[n], (BoxType *) text); } END_LOOP; } /*! * \brief Returns a string that has a bunch of information about the * program. * * Can be used for things like "about" dialog boxes. */ char * GetInfoString (void) { HID **hids; int i; static DynamicStringType info; static int first_time = 1; #define TAB " " if (first_time) { first_time = 0; DSAddString (&info, _("This is PCB, an interactive\n" "printed circuit board editor\n" "version ")); DSAddString (&info, VERSION "\n\n" "Compiled on " __DATE__ " at " __TIME__ "\n\n" "by harry eaton\n\n" "Copyright (C) Thomas Nau 1994, 1995, 1996, 1997\n" "Copyright (C) harry eaton 1998-2007\n" "Copyright (C) C. Scott Ananian 2001\n" "Copyright (C) DJ Delorie 2003, 2004, 2005, 2006, 2007, 2008\n" "Copyright (C) Dan McMahill 2003, 2004, 2005, 2006, 2007, 2008\n\n"); DSAddString (&info, _("It is licensed under the terms of the GNU\n" "General Public License version 2\n" "See the LICENSE file for more information\n\n" "For more information see:\n")); DSAddString (&info, _("PCB homepage: ")); DSAddString (&info, "http://pcb.geda-project.org\n"); DSAddString (&info, _("gEDA homepage: ")); DSAddString (&info, "http://www.geda-project.org\n"); DSAddString (&info, _("gEDA Wiki: ")); DSAddString (&info, "http://wiki.geda-project.org\n"); DSAddString (&info, _("\n----- Compile Time Options -----\n")); hids = hid_enumerate (); DSAddString (&info, _("GUI:\n")); for (i = 0; hids[i]; i++) { if (hids[i]->gui) { DSAddString (&info, TAB); DSAddString (&info, hids[i]->name); DSAddString (&info, " : "); DSAddString (&info, hids[i]->description); DSAddString (&info, "\n"); } } DSAddString (&info, _("Exporters:\n")); for (i = 0; hids[i]; i++) { if (hids[i]->exporter) { DSAddString (&info, TAB); DSAddString (&info, hids[i]->name); DSAddString (&info, " : "); DSAddString (&info, hids[i]->description); DSAddString (&info, "\n"); } } DSAddString (&info, _("Printers:\n")); for (i = 0; hids[i]; i++) { if (hids[i]->printer) { DSAddString (&info, TAB); DSAddString (&info, hids[i]->name); DSAddString (&info, " : "); DSAddString (&info, hids[i]->description); DSAddString (&info, "\n"); } } } #undef TAB return info.Data; } #ifdef MKDIR_IS_PCBMKDIR #error "Don't know how to create a directory on this system." #endif /*! * \brief mkdir() implentation, mostly for plugins, which don't have our * config.h. */ int pcb_mkdir (const char *path, int mode) { return MKDIR (path, mode); } /*! * \brief Returns a best guess about the orientation of an element. * * The value corresponds to the rotation; a difference is the right * value to pass to RotateElementLowLevel. * However, the actual value is no indication of absolute rotation; only * relative rotation is meaningful. * * \return a relative rotation for an element, useful only for comparing * two similar footprints. */ int ElementOrientation (ElementType *e) { Coord pin1x, pin1y, pin2x, pin2y, dx, dy; bool found_pin1 = 0; bool found_pin2 = 0; /* in case we don't find pin 1 or 2, make sure we have initialized these variables */ pin1x = 0; pin1y = 0; pin2x = 0; pin2y = 0; PIN_LOOP (e); { if (NSTRCMP (pin->Number, "1") == 0) { pin1x = pin->X; pin1y = pin->Y; found_pin1 = 1; } else if (NSTRCMP (pin->Number, "2") == 0) { pin2x = pin->X; pin2y = pin->Y; found_pin2 = 1; } } END_LOOP; PAD_LOOP (e); { if (NSTRCMP (pad->Number, "1") == 0) { pin1x = (pad->Point1.X + pad->Point2.X) / 2; pin1y = (pad->Point1.Y + pad->Point2.Y) / 2; found_pin1 = 1; } else if (NSTRCMP (pad->Number, "2") == 0) { pin2x = (pad->Point1.X + pad->Point2.X) / 2; pin2y = (pad->Point1.Y + pad->Point2.Y) / 2; found_pin2 = 1; } } END_LOOP; if (found_pin1 && found_pin2) { dx = pin2x - pin1x; dy = pin2y - pin1y; } else if (found_pin1 && (pin1x || pin1y)) { dx = pin1x; dy = pin1y; } else if (found_pin2 && (pin2x || pin2y)) { dx = pin2x; dy = pin2y; } else return 0; if (abs(dx) > abs(dy)) return dx > 0 ? 0 : 2; return dy > 0 ? 3 : 1; } int ActionListRotations(int argc, char **argv, Coord x, Coord y) { ELEMENT_LOOP (PCB->Data); { printf("%d %s\n", ElementOrientation(element), NAMEONPCB_NAME(element)); } END_LOOP; return 0; } HID_Action misc_action_list[] = { {"ListRotations", 0, ActionListRotations, 0,0}, }; REGISTER_ACTIONS (misc_action_list) pcb-4.2.2/src/smartdisperse.c0000664000076400007640000001661713533277055013063 00000000000000/*! * \file src/smartdisperse.c * * \brief Smart dispersion of elements. * * Improve the initial dispersion of elements by choosing an order based * on the netlist, rather than the arbitrary element order. This isn't * the same as a global autoplace, it's more of a linear autoplace. It * might make some useful local groupings. For example, you should not * have to chase all over the board to find the resistor that goes with * a given LED. * *
* *

Copyright.

\n * * \author Copyright (C) 2007 Ben Jackson based on * teardrops.c by Copyright (C) 2006 DJ Delorie as well * as the original action.c, and autoplace.c. * * Licensed under the terms of the GNU General Public * License, version 2 or later. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA * haceaton@aplcomm.jhuapl.edu */ #include #include #include "config.h" #include "global.h" #include "data.h" #include "hid.h" #include "misc.h" #include "create.h" #include "rtree.h" #include "undo.h" #include "rats.h" #include "error.h" #include "move.h" #include "draw.h" #include "set.h" #define GAP 10000 static Coord minx; static Coord miny; static Coord maxx; static Coord maxy; /*! * \brief Place one element. * * Must initialize statics above before calling for the first time. * * This is taken almost entirely from ActionDisperseElements, with cleanup */ static void place (ElementType *element) { Coord dx, dy; /* figure out how much to move the element */ dx = minx - element->BoundingBox.X1; dy = miny - element->BoundingBox.Y1; /* snap to the grid */ dx -= (element->MarkX + dx) % (long) (PCB->Grid); dx += (long) (PCB->Grid); dy -= (element->MarkY + dy) % (long) (PCB->Grid); dy += (long) (PCB->Grid); /* * and add one grid size so we make sure we always space by GAP or * more */ dx += (long) (PCB->Grid); /* Figure out if this row has room. If not, start a new row */ if (minx != GAP && GAP + element->BoundingBox.X2 + dx > PCB->MaxWidth) { miny = maxy + GAP; minx = GAP; place(element); /* recurse can't loop, now minx==GAP */ return; } /* move the element */ MoveElementLowLevel (PCB->Data, element, dx, dy); /* and add to the undo list so we can undo this operation */ AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy); /* keep track of how tall this row is */ minx += element->BoundingBox.X2 - element->BoundingBox.X1 + GAP; if (maxy < element->BoundingBox.Y2) { maxy = element->BoundingBox.Y2; } } /*! * \brief Return the X location of a connection's pad or pin within its * element. */ static Coord padDX (ConnectionType *conn) { ElementType *element = (ElementType *) conn->ptr1; AnyLineObjectType *line = (AnyLineObjectType *) conn->ptr2; return line->BoundingBox.X1 - (element->BoundingBox.X1 + element->BoundingBox.X2) / 2; } /*! * \brief Return true if ea,eb would be the best order, else eb,ea, * based on pad loc. */ static int padorder (ConnectionType *conna, ConnectionType *connb) { Coord dxa, dxb; dxa = padDX (conna); dxb = padDX (connb); /* there are other cases that merit rotation, ignore them for now */ if (dxa > 0 && dxb < 0) return 1; return 0; } /* ewww, these are actually arrays */ #define ELEMENT_N(DATA,ELT) ((ELT) - (DATA)->Element) #define VISITED(ELT) (visited[ELEMENT_N(PCB->Data, (ELT))]) #define IS_ELEMENT(CONN) ((CONN)->type == PAD_TYPE || (CONN)->type == PIN_TYPE) static const char smartdisperse_syntax[] = "SmartDisperse([All|Selected])"; /* %start-doc actions SmartDisperse The @code{SmartDisperse([All|Selected])} action is a special-purpose optimization for dispersing elements. Run with @code{:SmartDisperse()} or @code{:SmartDisperse(Selected)} (you can also say @code{:SmartDisperse(All)}, but that's the default). %end-doc */ static int smartdisperse (int argc, char **argv, Coord x, Coord y) { char *function = ARG(0); NetListType *Nets; char *visited; // PointerListType stack = { 0, 0, NULL }; int all; // int changed = 0; // int i; if (! function) { all = 1; } else if (strcmp(function, "All") == 0) { all = 1; } else if (strcmp(function, "Selected") == 0) { all = 0; } else { AFAIL (smartdisperse); } Nets = ProcNetlist (&PCB->NetlistLib); if (! Nets) { Message (_("Can't use SmartDisperse because no netlist is loaded.\n")); return 0; } /* remember which elements we finish with */ visited = calloc (PCB->Data->ElementN, sizeof(*visited)); /* if we're not doing all, mark the unselected elements as "visited" */ ELEMENT_LOOP (PCB->Data); { if (! (all || TEST_FLAG (SELECTEDFLAG, element))) { visited[n] = 1; } } END_LOOP; /* initialize variables for place() */ minx = GAP; miny = GAP; maxx = GAP; maxy = GAP; /* * Pick nets with two connections. This is the start of a more * elaborate algorithm to walk serial nets, but the datastructures * are too gross so I'm going with the 80% solution. */ NET_LOOP (Nets); { ConnectionType *conna, *connb; ElementType *ea, *eb; // ElementType *epp; if (net->ConnectionN != 2) continue; conna = &net->Connection[0]; connb = &net->Connection[1]; if (!IS_ELEMENT(conna) || !IS_ELEMENT(conna)) continue; ea = (ElementType *) conna->ptr1; eb = (ElementType *) connb->ptr1; /* place this pair if possible */ if (VISITED((GList *)ea) || VISITED((GList *)eb)) continue; VISITED ((GList *)ea) = 1; VISITED ((GList *)eb) = 1; /* a weak attempt to get the linked pads side-by-side */ if (padorder(conna, connb)) { place ((ElementType *) ea); place ((ElementType *) eb); } else { place (eb); place (ea); } } END_LOOP; /* Place larger nets, still grouping by net */ NET_LOOP (Nets); { CONNECTION_LOOP (net); { ElementType *element; if (! IS_ELEMENT(connection)) continue; element = (ElementType *) connection->ptr1; /* place this one if needed */ if (VISITED ((GList *) element)) continue; VISITED ((GList *) element) = 1; place (element); } END_LOOP; } END_LOOP; /* Place up anything else */ ELEMENT_LOOP (PCB->Data); { if (! visited[n]) { place (element); } } END_LOOP; free (visited); IncrementUndoSerialNumber (); Redraw (); SetChangedFlag (1); return 0; } static HID_Action smartdisperse_action_list[] = { {"smartdisperse", NULL, smartdisperse, NULL, NULL} }; REGISTER_ACTIONS (smartdisperse_action_list) void hid_smartdisperse_init () { register_smartdisperse_action_list (); } pcb-4.2.2/src/layerflags.c0000664000076400007640000001345513434555140012316 00000000000000/*! * \file src/layerflags.c * * \brief Functions for changing layer flags. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2007 DJ Delorie * * Copyright (C) 2015 Markus "Traumflug" Hitter * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "globalconst.h" #include "global.h" #include "compat.h" #include "data.h" #include "error.h" #include "hid.h" #include "strflags.h" #include "layerflags.h" /*! * \brief These are the names of all the Layertypes defined in hid.h. * * Order here has to match the order of typedef enum LayertypeType there. * They're used for parsing/writing layer types from/to the layout file. */ static char *layertype_name[LT_NUM_LAYERTYPES + 1] = { "copper", /* LT_COPPER */ "silk", /* LT_SILK */ "mask", /* LT_MASK */ "paste", /* LT_PASTE */ "outline", /* LT_OUTLINE */ "route", /* LT_ROUTE */ "keepout", /* LT_KEEPOUT */ "fab", /* LT_FAB */ "assy", /* LT_ASSY */ "notes", /* LT_NOTES */ "no_type" /* LT_NUM_LAYERTYPES */ }; LayertypeType string_to_layertype (const char *flagstring, int (*error) (const char *msg)) { LayertypeType type = 0; if (*flagstring == '"') flagstring++; while (flagstring > (char *)1 && strlen (flagstring) > 1) { for (type = 0; type < LT_NUM_LAYERTYPES; type++) { if (strcmp (flagstring, layertype_name[type]) == 0) break; } if (type == LT_NUM_LAYERTYPES) flagstring = strchr (flagstring, ',') + 1; else break; } return type; } const char * layertype_to_string (LayertypeType type) { const char *rv = ""; if (type < LT_NUM_LAYERTYPES) rv = layertype_name[type]; return rv; } /*! * \brief Given a layer without type, try to guess its type, mostly from * its name. * * This is used by parse_y.y for compatibility with old file formats and * _not_ used when such flags are already present in the file. */ LayertypeType guess_layertype (const char *name, int layer_number, DataType *data) { LayertypeType type; /* First try to find known (partial) matches. */ for (type = 0; type < LT_NUM_LAYERTYPES; type++) { if (strcasestr (name, layertype_name[type])) break; } /* Nothing found? Then it's likely copper. */ if (type == LT_NUM_LAYERTYPES) type = LT_COPPER; return type; } /* --------------------------------------------------------------------------- */ static const char listlayertypes_syntax[] = N_("ListLayertypes()"); static const char listlayertypes_help[] = N_("List all available layertypes.\n"); /* %start-doc actions ListLayertypes Lists all available layer types. These are the valid types for the second argument of @pxref{SetLayertype Action} or when editing the layout file with a text editor. %end-doc */ static int ActionListLayertypes (int argc, char **argv, Coord x, Coord y) { LayertypeType type; Message (N_("Available layer types:\n")); for (type = 0; type < LT_NUM_LAYERTYPES; type++) Message (" %s (%d)\n", layertype_name[type], type); return 0; } /* --------------------------------------------------------------------------- */ static const char setlayertype_syntax[] = N_("SetLayertype(layer, type)"); static const char setlayertype_help[] = N_("Sets the type of a layer. Type can be given by name or by number.\n" "For a list of available types, run ListLayertypes()."); /* %start-doc actions SetLayertype Layers can have various types, like @emph{copper}, @emph{silk} or @emph{outline}. Behaviour of GUI and exporters largely depend on these types. For example, searching for electrical connections searches only layers of type @emph{copper}, all other layers are ignored. For a list of available types see @pxref{ListLayertypes Action}. %end-doc */ int ActionSetLayertype (int argc, char **argv, Coord x, Coord y) { int index; LayertypeType type; if (argc != 2) AFAIL (setlayertype); /* layer array is zero-based, file format counts layers starting at 1. */ index = atoi (argv[0]) - 1; if (index < 0 || index >= max_copper_layer + SILK_LAYER) { Message (N_("Layer index %d out of range, must be 0 ... %d\n"), index + 1, max_copper_layer + SILK_LAYER); return 1; } if (isdigit (argv[1][0])) type = atoi (argv[1]); else type = string_to_layertype (argv[1], NULL); if (type < 0 || type >= LT_NUM_LAYERTYPES) { Message (N_("Invalid layer type (%d) requested. " "See ListLayertypes() for a list.\n"), type); return 1; } PCB->Data->Layer[index].Type = type; return 0; } HID_Action layerflags_action_list[] = { {"ListLayertypes", 0, ActionListLayertypes, listlayertypes_help, listlayertypes_syntax} , {"SetLayertype", 0, ActionSetLayertype, setlayertype_help, setlayertype_syntax} }; REGISTER_ACTIONS (layerflags_action_list) pcb-4.2.2/src/data.c0000664000076400007640000000342513434555140011072 00000000000000/*! * \file src/data.c * * \brief Just defines common identifiers. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "data.h" #ifdef HAVE_LIBDMALLOC #include #endif /* --------------------------------------------------------------------------- * some shared identifiers */ CrosshairType Crosshair; /*!< information about cursor settings. */ MarkType Marked; /*!< a cross-hair mark. */ OutputType Output; /*!< some widgets ... used for drawing. */ PCBType *PCB; /*!< pointer to layout struct. */ char *Progname; SettingType Settings; int LayerStack[MAX_LAYER]; /*!< determines the layer draw order. */ BufferType Buffers[MAX_BUFFER]; /*!< my buffers. */ LibraryType Library; /*!< the library. */ bool Bumped; /*!< if the undo serial number has changed. */ int addedLines; pcb-4.2.2/src/pcb-menu.res.h0000664000076400007640000006217513611113566012472 00000000000000# 223 "pcb-menu.res" char *s = N_(" Center"); # 154 "pcb-menu.res" char *s = N_(" Change text on layout"); # 225 "pcb-menu.res" char *s = N_(" Crosshair"); # 159 "pcb-menu.res" char *s = N_(" CurrentLayer"); # 156 "pcb-menu.res" char *s = N_(" Edit name of active layer"); # 155 "pcb-menu.res" char *s = N_(" Edit name of layout"); # 160 "pcb-menu.res" char *s = N_(" Element"); # 158 "pcb-menu.res" char *s = N_(" Layout"); # 224 "pcb-menu.res" char *s = N_(" Mark"); # 51 "pcb-menu.res" char *s = N_(" a single element"); # 52 "pcb-menu.res" char *s = N_(" all elements"); # 53 "pcb-menu.res" char *s = N_(" unused pins"); # 303 "pcb-menu.res" char *s = N_("#1"); # 304 "pcb-menu.res" char *s = N_("#2"); # 305 "pcb-menu.res" char *s = N_("#3"); # 306 "pcb-menu.res" char *s = N_("#4"); # 307 "pcb-menu.res" char *s = N_("#5"); # 201 "pcb-menu.res" char *s = N_("'All-direction' lines"); # 201 "pcb-menu.res" char *s = N_("."); # 430 "pcb-menu.res" char *s = N_("/"); # 112 "pcb-menu.res" char *s = N_("0.01 mm"); # 113 "pcb-menu.res" char *s = N_("0.05 mm"); # 104 "pcb-menu.res" char *s = N_("0.1 mil"); # 114 "pcb-menu.res" char *s = N_("0.1 mm"); # 115 "pcb-menu.res" char *s = N_("0.25 mm"); # 116 "pcb-menu.res" char *s = N_("0.5 mm"); # 105 "pcb-menu.res" char *s = N_("1 mil"); # 117 "pcb-menu.res" char *s = N_("1 mm"); # 107 "pcb-menu.res" char *s = N_("10 mil"); # 110 "pcb-menu.res" char *s = N_("100 mil"); # 108 "pcb-menu.res" char *s = N_("25 mil"); # 106 "pcb-menu.res" char *s = N_("5 mil"); # 109 "pcb-menu.res" char *s = N_("50 mil"); # 195 "pcb-menu.res" char *s = N_(":"); # 201 "pcb-menu.res" char *s = N_("."); # 430 "pcb-menu.res" char *s = N_("/"); # 195 "pcb-menu.res" char *s = N_(":"); # 332 "pcb-menu.res" char *s = N_("="); # 353 "pcb-menu.res" char *s = N_("BackSpace"); # 252 "pcb-menu.res" char *s = N_("Delete"); # 436 "pcb-menu.res" char *s = N_("Down"); # 443 "pcb-menu.res" char *s = N_("Enter"); # 193 "pcb-menu.res" char *s = N_("Escape"); # 177 "pcb-menu.res" char *s = N_("F1"); # 187 "pcb-menu.res" char *s = N_("F10"); # 188 "pcb-menu.res" char *s = N_("F11"); # 192 "pcb-menu.res" char *s = N_("F12"); # 178 "pcb-menu.res" char *s = N_("F2"); # 179 "pcb-menu.res" char *s = N_("F3"); # 180 "pcb-menu.res" char *s = N_("F4"); # 181 "pcb-menu.res" char *s = N_("F5"); # 182 "pcb-menu.res" char *s = N_("F6"); # 184 "pcb-menu.res" char *s = N_("F7"); # 185 "pcb-menu.res" char *s = N_("F8"); # 186 "pcb-menu.res" char *s = N_("F9"); # 189 "pcb-menu.res" char *s = N_("Insert"); # 437 "pcb-menu.res" char *s = N_("Left"); # 438 "pcb-menu.res" char *s = N_("Right"); # 60 "pcb-menu.res" char *s = N_("Tab"); # 435 "pcb-menu.res" char *s = N_("Up"); # 432 "pcb-menu.res" char *s = N_("["); # 433 "pcb-menu.res" char *s = N_("]"); # 87 "pcb-menu.res" char *s = N_("`"); # 390 "pcb-menu.res" char *s = N_("a"); # 391 "pcb-menu.res" char *s = N_("b"); # 64 "pcb-menu.res" char *s = N_("c"); # 219 "pcb-menu.res" char *s = N_("d"); # 318 "pcb-menu.res" char *s = N_("e"); # 392 "pcb-menu.res" char *s = N_("f"); # 120 "pcb-menu.res" char *s = N_("g"); # 393 "pcb-menu.res" char *s = N_("h"); # 396 "pcb-menu.res" char *s = N_("j"); # 398 "pcb-menu.res" char *s = N_("k"); # 402 "pcb-menu.res" char *s = N_("l"); # 404 "pcb-menu.res" char *s = N_("m"); # 154 "pcb-menu.res" char *s = N_("n"); # 317 "pcb-menu.res" char *s = N_("o"); # 414 "pcb-menu.res" char *s = N_("p"); # 416 "pcb-menu.res" char *s = N_("q"); # 351 "pcb-menu.res" char *s = N_("r"); # 417 "pcb-menu.res" char *s = N_("s"); # 431 "pcb-menu.res" char *s = N_("space"); # 421 "pcb-menu.res" char *s = N_("t"); # 138 "pcb-menu.res" char *s = N_("u"); # 86 "pcb-menu.res" char *s = N_("v"); # 428 "pcb-menu.res" char *s = N_("w"); # 334 "pcb-menu.res" char *s = N_("y"); # 83 "pcb-menu.res" char *s = N_("z"); # 214 "pcb-menu.res" char *s = N_("|"); # 332 "pcb-menu.res" char *s = N_("="); # 390 "pcb-menu.res" char *s = N_("A"); # 32 "pcb-menu.res" char *s = N_("About..."); # 428 "pcb-menu.res" char *s = N_("Add All Rats"); # 132 "pcb-menu.res" char *s = N_("Add new layer"); # 427 "pcb-menu.res" char *s = N_("AddRats Selected"); # 407 "pcb-menu.res" char *s = N_("AddRats to selected pins"); # 338 "pcb-menu.res" char *s = N_("All"); # 241 "pcb-menu.res" char *s = N_("All objects"); # 420 "pcb-menu.res" char *s = N_("Alt Shifts"); # 426 "pcb-menu.res" char *s = N_("Alt Shiftv"); # 151 "pcb-menu.res" char *s = N_("Alt-A"); # 256 "pcb-menu.res" char *s = N_("Alt-R"); # 419 "pcb-menu.res" char *s = N_("Alt-S"); # 420 "pcb-menu.res" char *s = N_("Alt-Shift-S"); # 426 "pcb-menu.res" char *s = N_("Alt-Shift-V"); # 425 "pcb-menu.res" char *s = N_("Alt-V"); # 429 "pcb-menu.res" char *s = N_("Alt-Z"); # 151 "pcb-menu.res" char *s = N_("Alta"); # 256 "pcb-menu.res" char *s = N_("Altr"); # 419 "pcb-menu.res" char *s = N_("Alts"); # 425 "pcb-menu.res" char *s = N_("Altv"); # 429 "pcb-menu.res" char *s = N_("Altz"); # 344 "pcb-menu.res" char *s = N_("Apply vendor drill mapping"); # 292 "pcb-menu.res" char *s = N_("Arbitrarily Rotate Buffer"); # 179 "pcb-menu.res" char *s = N_("Arc"); # 431 "pcb-menu.res" char *s = N_("Arrow"); # 206 "pcb-menu.res" char *s = N_("Auto enforce DRC clearance"); # 202 "pcb-menu.res" char *s = N_("Auto swap line start angle"); # 326 "pcb-menu.res" char *s = N_("Auto-Optimize"); # 248 "pcb-menu.res" char *s = N_("Auto-place selected elements"); # 322 "pcb-menu.res" char *s = N_("Auto-route all rats"); # 321 "pcb-menu.res" char *s = N_("Auto-route selected rats"); # 210 "pcb-menu.res" char *s = N_("Auto-zero delta measurements"); # 391 "pcb-menu.res" char *s = N_("B"); # 353 "pcb-menu.res" char *s = N_("Backspace"); # 447 "pcb-menu.res" char *s = N_("Board Layout"); # 162 "pcb-menu.res" char *s = N_("Board Sizes"); # 299 "pcb-menu.res" char *s = N_("Break buffer elements to pieces"); # 184 "pcb-menu.res" char *s = N_("Buffer"); # 171 "pcb-menu.res" char *s = N_("Buried from"); # 172 "pcb-menu.res" char *s = N_("Buried to"); # 64 "pcb-menu.res" char *s = N_("C"); # 48 "pcb-menu.res" char *s = N_("Calibrate Printer..."); # 193 "pcb-menu.res" char *s = N_("Cancel"); # 64 "pcb-menu.res" char *s = N_("Center cursor"); # 271 "pcb-menu.res" char *s = N_("Change drilling hole of selected objects"); # 259 "pcb-menu.res" char *s = N_("Change size of selected objects"); # 277 "pcb-menu.res" char *s = N_("Change square-flag of selected objects"); # 419 "pcb-menu.res" char *s = N_("ChangeDrill +5 mil"); # 420 "pcb-menu.res" char *s = N_("ChangeDrill -5 mil"); # 395 "pcb-menu.res" char *s = N_("ChangeHole Object"); # 396 "pcb-menu.res" char *s = N_("ChangeJoin Object"); # 397 "pcb-menu.res" char *s = N_("ChangeJoin SelectedObject"); # 413 "pcb-menu.res" char *s = N_("ChangeOctagon Object"); # 417 "pcb-menu.res" char *s = N_("ChangeSize +"); # 418 "pcb-menu.res" char *s = N_("ChangeSize -"); # 416 "pcb-menu.res" char *s = N_("ChangeSquare Object"); # 216 "pcb-menu.res" char *s = N_("Check polygons"); # 398 "pcb-menu.res" char *s = N_("Clear Object +"); # 399 "pcb-menu.res" char *s = N_("Clear Object -"); # 400 "pcb-menu.res" char *s = N_("Clear Selected +"); # 401 "pcb-menu.res" char *s = N_("Clear Selected -"); # 297 "pcb-menu.res" char *s = N_("Clear buffer"); # 140 "pcb-menu.res" char *s = N_("Clear undo-buffer"); # 443 "pcb-menu.res" char *s = N_("Click"); # 195 "pcb-menu.res" char *s = N_("Command"); # 298 "pcb-menu.res" char *s = N_("Convert buffer to element"); # 253 "pcb-menu.res" char *s = N_("Convert selection to element"); # 191 "pcb-menu.res" char *s = N_("Copy"); # 283 "pcb-menu.res" char *s = N_("Copy selection to buffer"); # 205 "pcb-menu.res" char *s = N_("Crosshair shows DRC clearance"); # 204 "pcb-menu.res" char *s = N_("Crosshair snaps to pins and pads"); # 63 "pcb-menu.res" char *s = N_("Ctrl ShiftTab"); # 171 "pcb-menu.res" char *s = N_("Ctrl Shiftf"); # 215 "pcb-menu.res" char *s = N_("Ctrl Shiftp"); # 172 "pcb-menu.res" char *s = N_("Ctrl Shiftt"); # 147 "pcb-menu.res" char *s = N_("Ctrl-C"); # 311 "pcb-menu.res" char *s = N_("Ctrl-F"); # 395 "pcb-menu.res" char *s = N_("Ctrl-H"); # 400 "pcb-menu.res" char *s = N_("Ctrl-K"); # 405 "pcb-menu.res" char *s = N_("Ctrl-M"); # 55 "pcb-menu.res" char *s = N_("Ctrl-N"); # 413 "pcb-menu.res" char *s = N_("Ctrl-O"); # 248 "pcb-menu.res" char *s = N_("Ctrl-P"); # 57 "pcb-menu.res" char *s = N_("Ctrl-Q"); # 348 "pcb-menu.res" char *s = N_("Ctrl-R"); # 33 "pcb-menu.res" char *s = N_("Ctrl-S"); # 215 "pcb-menu.res" char *s = N_("Ctrl-Shift-P"); # 63 "pcb-menu.res" char *s = N_("Ctrl-Shift-Tab"); # 62 "pcb-menu.res" char *s = N_("Ctrl-Tab"); # 148 "pcb-menu.res" char *s = N_("Ctrl-V"); # 144 "pcb-menu.res" char *s = N_("Ctrl-X"); # 62 "pcb-menu.res" char *s = N_("CtrlTab"); # 147 "pcb-menu.res" char *s = N_("Ctrlc"); # 311 "pcb-menu.res" char *s = N_("Ctrlf"); # 395 "pcb-menu.res" char *s = N_("Ctrlh"); # 400 "pcb-menu.res" char *s = N_("Ctrlk"); # 405 "pcb-menu.res" char *s = N_("Ctrlm"); # 55 "pcb-menu.res" char *s = N_("Ctrln"); # 413 "pcb-menu.res" char *s = N_("Ctrlo"); # 248 "pcb-menu.res" char *s = N_("Ctrlp"); # 57 "pcb-menu.res" char *s = N_("Ctrlq"); # 348 "pcb-menu.res" char *s = N_("Ctrlr"); # 33 "pcb-menu.res" char *s = N_("Ctrls"); # 148 "pcb-menu.res" char *s = N_("Ctrlv"); # 144 "pcb-menu.res" char *s = N_("Ctrlx"); # 128 "pcb-menu.res" char *s = N_("Current Layer"); # 285 "pcb-menu.res" char *s = N_("Cut selection to buffer"); # 430 "pcb-menu.res" char *s = N_("Cycle Clip"); # 219 "pcb-menu.res" char *s = N_("D"); # 327 "pcb-menu.res" char *s = N_("Debumpify"); # 252 "pcb-menu.res" char *s = N_("Delete"); # 131 "pcb-menu.res" char *s = N_("Delete current layer"); # 252 "pcb-menu.res" char *s = N_("Delete selected objects"); # 68 "pcb-menu.res" char *s = N_("Description"); # 342 "pcb-menu.res" char *s = N_("Design Rule Checker"); # 249 "pcb-menu.res" char *s = N_("Disperse all elements"); # 100 "pcb-menu.res" char *s = N_("Display grid"); # 67 "pcb-menu.res" char *s = N_("Displayed element-name..."); # 440 "pcb-menu.res" char *s = N_("Down"); # 318 "pcb-menu.res" char *s = N_("E"); # 157 "pcb-menu.res" char *s = N_("Edit Attributes..."); # 126 "pcb-menu.res" char *s = N_("Edit Layer Groups"); # 153 "pcb-menu.res" char *s = N_("Edit Names..."); # 199 "pcb-menu.res" char *s = N_("Edit layer groupings"); # 166 "pcb-menu.res" char *s = N_("Edit..."); # 278 "pcb-menu.res" char *s = N_("Elements"); # 220 "pcb-menu.res" char *s = N_("Enable vendor drill mapping"); # 443 "pcb-menu.res" char *s = N_("Enter"); # 318 "pcb-menu.res" char *s = N_("Erase rats-nest"); # 319 "pcb-menu.res" char *s = N_("Erase selected rats"); # 193 "pcb-menu.res" char *s = N_("Esc"); # 47 "pcb-menu.res" char *s = N_("Export layout..."); # 392 "pcb-menu.res" char *s = N_("F"); # 177 "pcb-menu.res" char *s = N_("F1"); # 187 "pcb-menu.res" char *s = N_("F10"); # 188 "pcb-menu.res" char *s = N_("F11"); # 192 "pcb-menu.res" char *s = N_("F12"); # 178 "pcb-menu.res" char *s = N_("F2"); # 179 "pcb-menu.res" char *s = N_("F3"); # 180 "pcb-menu.res" char *s = N_("F4"); # 181 "pcb-menu.res" char *s = N_("F5"); # 182 "pcb-menu.res" char *s = N_("F6"); # 184 "pcb-menu.res" char *s = N_("F7"); # 185 "pcb-menu.res" char *s = N_("F8"); # 186 "pcb-menu.res" char *s = N_("F9"); # 392 "pcb-menu.res" char *s = N_("Find Connections"); # 391 "pcb-menu.res" char *s = N_("Flip Object"); # 61 "pcb-menu.res" char *s = N_("Flip left/right"); # 60 "pcb-menu.res" char *s = N_("Flip up/down"); # 337 "pcb-menu.res" char *s = N_("Found"); # 120 "pcb-menu.res" char *s = N_("G"); # 349 "pcb-menu.res" char *s = N_("Generate drill summary"); # 348 "pcb-menu.res" char *s = N_("Generate object report"); # 335 "pcb-menu.res" char *s = N_("Global Puller"); # 120 "pcb-menu.res" char *s = N_("Grid +"); # 119 "pcb-menu.res" char *s = N_("Grid -"); # 393 "pcb-menu.res" char *s = N_("H"); # 73 "pcb-menu.res" char *s = N_("Hide Names"); # 37 "pcb-menu.res" char *s = N_("Import Schematics"); # 221 "pcb-menu.res" char *s = N_("Import Settings"); # 189 "pcb-menu.res" char *s = N_("Insert"); # 189 "pcb-menu.res" char *s = N_("Insert Point"); # 396 "pcb-menu.res" char *s = N_("J"); # 398 "pcb-menu.res" char *s = N_("K"); # 352 "pcb-menu.res" char *s = N_("Key Bindings"); # 402 "pcb-menu.res" char *s = N_("L"); # 198 "pcb-menu.res" char *s = N_("Layer groups"); # 441 "pcb-menu.res" char *s = N_("Left"); # 448 "pcb-menu.res" char *s = N_("Library"); # 178 "pcb-menu.res" char *s = N_("Line"); # 402 "pcb-menu.res" char *s = N_("Line Tool size +"); # 403 "pcb-menu.res" char *s = N_("Line Tool size -"); # 261 "pcb-menu.res" char *s = N_("Lines +10 mil"); # 260 "pcb-menu.res" char *s = N_("Lines -10 mil"); # 42 "pcb-menu.res" char *s = N_("Load element data to paste-buffer"); # 41 "pcb-menu.res" char *s = N_("Load layout"); # 43 "pcb-menu.res" char *s = N_("Load layout data to paste-buffer"); # 44 "pcb-menu.res" char *s = N_("Load netlist file"); # 45 "pcb-menu.res" char *s = N_("Load vendor resource file"); # 192 "pcb-menu.res" char *s = N_("Lock"); # 71 "pcb-menu.res" char *s = N_("Lock Names"); # 311 "pcb-menu.res" char *s = N_("Lookup connection to object"); # 404 "pcb-menu.res" char *s = N_("M"); # 405 "pcb-menu.res" char *s = N_("MarkCrosshair"); # 449 "pcb-menu.res" char *s = N_("Message Log"); # 294 "pcb-menu.res" char *s = N_("Mirror buffer (left/right)"); # 293 "pcb-menu.res" char *s = N_("Mirror buffer (up/down)"); # 333 "pcb-menu.res" char *s = N_("Miter"); # 190 "pcb-menu.res" char *s = N_("Move"); # 404 "pcb-menu.res" char *s = N_("Move Object to current layer"); # 134 "pcb-menu.res" char *s = N_("Move current layer down"); # 133 "pcb-menu.res" char *s = N_("Move current layer up"); # 250 "pcb-menu.res" char *s = N_("Move selected elements to other side"); # 251 "pcb-menu.res" char *s = N_("Move selected to current layer"); # 154 "pcb-menu.res" char *s = N_("N"); # 450 "pcb-menu.res" char *s = N_("Netlist"); # 222 "pcb-menu.res" char *s = N_("New elements added at..."); # 211 "pcb-menu.res" char *s = N_("New lines, arcs clear polygons"); # 212 "pcb-menu.res" char *s = N_("New polygons are full ones"); # 102 "pcb-menu.res" char *s = N_("No Grid"); # 176 "pcb-menu.res" char *s = N_("None"); # 317 "pcb-menu.res" char *s = N_("O"); # 72 "pcb-menu.res" char *s = N_("Only Names"); # 340 "pcb-menu.res" char *s = N_("Only autorouted nets"); # 76 "pcb-menu.res" char *s = N_("Open pinout menu"); # 316 "pcb-menu.res" char *s = N_("Optimize rats-nest"); # 255 "pcb-menu.res" char *s = N_("Optimize selected rats"); # 203 "pcb-menu.res" char *s = N_("Orthogonal moves"); # 331 "pcb-menu.res" char *s = N_("Orthopull"); # 414 "pcb-menu.res" char *s = N_("P"); # 243 "pcb-menu.res" char *s = N_("Pads"); # 263 "pcb-menu.res" char *s = N_("Pads +10 mil"); # 262 "pcb-menu.res" char *s = N_("Pads -10 mil"); # 287 "pcb-menu.res" char *s = N_("Paste buffer to layout"); # 451 "pcb-menu.res" char *s = N_("Pinout"); # 218 "pcb-menu.res" char *s = N_("Pinout shows number"); # 279 "pcb-menu.res" char *s = N_("Pins"); # 275 "pcb-menu.res" char *s = N_("Pins +10 mil"); # 274 "pcb-menu.res" char *s = N_("Pins -10 mil"); # 219 "pcb-menu.res" char *s = N_("Pins/Via show Name/Number"); # 182 "pcb-menu.res" char *s = N_("Polygon"); # 415 "pcb-menu.res" char *s = N_("Polygon Close"); # 183 "pcb-menu.res" char *s = N_("Polygon Hole"); # 414 "pcb-menu.res" char *s = N_("Polygon PreviousPoint"); # 46 "pcb-menu.res" char *s = N_("Print layout..."); # 334 "pcb-menu.res" char *s = N_("Puller"); # 416 "pcb-menu.res" char *s = N_("Q"); # 57 "pcb-menu.res" char *s = N_("Quit Program"); # 351 "pcb-menu.res" char *s = N_("R"); # 101 "pcb-menu.res" char *s = N_("Realign grid"); # 181 "pcb-menu.res" char *s = N_("Rectangle"); # 139 "pcb-menu.res" char *s = N_("Redo last undone operation"); # 69 "pcb-menu.res" char *s = N_("Reference Designator"); # 353 "pcb-menu.res" char *s = N_("Remove"); # 373 "pcb-menu.res" char *s = N_("Remove Connected"); # 350 "pcb-menu.res" char *s = N_("Report found pins/pads"); # 351 "pcb-menu.res" char *s = N_("Report net length"); # 209 "pcb-menu.res" char *s = N_("Require unique element names"); # 314 "pcb-menu.res" char *s = N_("Reset all connections"); # 313 "pcb-menu.res" char *s = N_("Reset scanned lines/polygons"); # 312 "pcb-menu.res" char *s = N_("Reset scanned pads/pins/vias"); # 35 "pcb-menu.res" char *s = N_("Revert"); # 442 "pcb-menu.res" char *s = N_("Right"); # 324 "pcb-menu.res" char *s = N_("Rip up all auto-routed tracks"); # 257 "pcb-menu.res" char *s = N_("Rip up selected auto-routed tracks"); # 186 "pcb-menu.res" char *s = N_("Rotate"); # 289 "pcb-menu.res" char *s = N_("Rotate buffer 90 deg CCW"); # 291 "pcb-menu.res" char *s = N_("Rotate buffer 90 deg CW"); # 163 "pcb-menu.res" char *s = N_("Route Styles"); # 208 "pcb-menu.res" char *s = N_("Rubber band mode"); # 417 "pcb-menu.res" char *s = N_("S"); # 300 "pcb-menu.res" char *s = N_("Save buffer elements to file"); # 50 "pcb-menu.res" char *s = N_("Save connection data of..."); # 33 "pcb-menu.res" char *s = N_("Save layout"); # 34 "pcb-menu.res" char *s = N_("Save layout as..."); # 234 "pcb-menu.res" char *s = N_("Select all connected objects"); # 233 "pcb-menu.res" char *s = N_("Select all found objects"); # 151 "pcb-menu.res" char *s = N_("Select all visible"); # 232 "pcb-menu.res" char *s = N_("Select all visible objects"); # 240 "pcb-menu.res" char *s = N_("Select by name"); # 302 "pcb-menu.res" char *s = N_("Select current buffer"); # 406 "pcb-menu.res" char *s = N_("Select shortest rat"); # 336 "pcb-menu.res" char *s = N_("Selected"); # 227 "pcb-menu.res" char *s = N_("Set Dispersion"); # 390 "pcb-menu.res" char *s = N_("Set Same"); # 150 "pcb-menu.res" char *s = N_("Shift Alta"); # 34 "pcb-menu.res" char *s = N_("Shift Ctrl-S"); # 401 "pcb-menu.res" char *s = N_("Shift Ctrlk"); # 34 "pcb-menu.res" char *s = N_("Shift Ctrls"); # 140 "pcb-menu.res" char *s = N_("Shift Ctrlu"); # 424 "pcb-menu.res" char *s = N_("Shift Ctrlv"); # 303 "pcb-menu.res" char *s = N_("Shift-1"); # 304 "pcb-menu.res" char *s = N_("Shift-2"); # 305 "pcb-menu.res" char *s = N_("Shift-3"); # 306 "pcb-menu.res" char *s = N_("Shift-4"); # 307 "pcb-menu.res" char *s = N_("Shift-5"); # 326 "pcb-menu.res" char *s = N_("Shift-="); # 150 "pcb-menu.res" char *s = N_("Shift-Alt-A"); # 250 "pcb-menu.res" char *s = N_("Shift-B"); # 356 "pcb-menu.res" char *s = N_("Shift-Backspace"); # 401 "pcb-menu.res" char *s = N_("Shift-Ctrl-K"); # 140 "pcb-menu.res" char *s = N_("Shift-Ctrl-U"); # 424 "pcb-menu.res" char *s = N_("Shift-Ctrl-V"); # 451 "pcb-menu.res" char *s = N_("Shift-D"); # 373 "pcb-menu.res" char *s = N_("Shift-Delete"); # 319 "pcb-menu.res" char *s = N_("Shift-E"); # 314 "pcb-menu.res" char *s = N_("Shift-F"); # 290 "pcb-menu.res" char *s = N_("Shift-F7"); # 119 "pcb-menu.res" char *s = N_("Shift-G"); # 394 "pcb-menu.res" char *s = N_("Shift-H"); # 397 "pcb-menu.res" char *s = N_("Shift-J"); # 399 "pcb-menu.res" char *s = N_("Shift-K"); # 403 "pcb-menu.res" char *s = N_("Shift-L"); # 251 "pcb-menu.res" char *s = N_("Shift-M"); # 406 "pcb-menu.res" char *s = N_("Shift-N"); # 407 "pcb-menu.res" char *s = N_("Shift-O"); # 415 "pcb-menu.res" char *s = N_("Shift-P"); # 139 "pcb-menu.res" char *s = N_("Shift-R"); # 418 "pcb-menu.res" char *s = N_("Shift-S"); # 422 "pcb-menu.res" char *s = N_("Shift-T"); # 61 "pcb-menu.res" char *s = N_("Shift-Tab"); # 423 "pcb-menu.res" char *s = N_("Shift-V"); # 427 "pcb-menu.res" char *s = N_("Shift-W"); # 84 "pcb-menu.res" char *s = N_("Shift-Z"); # 303 "pcb-menu.res" char *s = N_("Shift1"); # 304 "pcb-menu.res" char *s = N_("Shift2"); # 305 "pcb-menu.res" char *s = N_("Shift3"); # 306 "pcb-menu.res" char *s = N_("Shift4"); # 307 "pcb-menu.res" char *s = N_("Shift5"); # 326 "pcb-menu.res" char *s = N_("Shift="); # 356 "pcb-menu.res" char *s = N_("ShiftBackSpace"); # 373 "pcb-menu.res" char *s = N_("ShiftDelete"); # 440 "pcb-menu.res" char *s = N_("ShiftDown"); # 290 "pcb-menu.res" char *s = N_("ShiftF7"); # 441 "pcb-menu.res" char *s = N_("ShiftLeft"); # 442 "pcb-menu.res" char *s = N_("ShiftRight"); # 61 "pcb-menu.res" char *s = N_("ShiftTab"); # 439 "pcb-menu.res" char *s = N_("ShiftUp"); # 250 "pcb-menu.res" char *s = N_("Shiftb"); # 451 "pcb-menu.res" char *s = N_("Shiftd"); # 319 "pcb-menu.res" char *s = N_("Shifte"); # 314 "pcb-menu.res" char *s = N_("Shiftf"); # 119 "pcb-menu.res" char *s = N_("Shiftg"); # 394 "pcb-menu.res" char *s = N_("Shifth"); # 397 "pcb-menu.res" char *s = N_("Shiftj"); # 399 "pcb-menu.res" char *s = N_("Shiftk"); # 403 "pcb-menu.res" char *s = N_("Shiftl"); # 251 "pcb-menu.res" char *s = N_("Shiftm"); # 406 "pcb-menu.res" char *s = N_("Shiftn"); # 407 "pcb-menu.res" char *s = N_("Shifto"); # 415 "pcb-menu.res" char *s = N_("Shiftp"); # 139 "pcb-menu.res" char *s = N_("Shiftr"); # 418 "pcb-menu.res" char *s = N_("Shifts"); # 422 "pcb-menu.res" char *s = N_("Shiftt"); # 423 "pcb-menu.res" char *s = N_("Shiftv"); # 427 "pcb-menu.res" char *s = N_("Shiftw"); # 84 "pcb-menu.res" char *s = N_("Shiftz"); # 213 "pcb-menu.res" char *s = N_("Show autorouter trials"); # 65 "pcb-menu.res" char *s = N_("Show soldermask"); # 123 "pcb-menu.res" char *s = N_("Shown Layers"); # 332 "pcb-menu.res" char *s = N_("SimpleOpts"); # 431 "pcb-menu.res" char *s = N_("Space"); # 62 "pcb-menu.res" char *s = N_("Spin 180°"); # 55 "pcb-menu.res" char *s = N_("Start new layout"); # 440 "pcb-menu.res" char *s = N_("Step +Down"); # 441 "pcb-menu.res" char *s = N_("Step +Left"); # 442 "pcb-menu.res" char *s = N_("Step +Right"); # 439 "pcb-menu.res" char *s = N_("Step +Up"); # 436 "pcb-menu.res" char *s = N_("Step Down"); # 437 "pcb-menu.res" char *s = N_("Step Left"); # 438 "pcb-menu.res" char *s = N_("Step Right"); # 435 "pcb-menu.res" char *s = N_("Step Up"); # 63 "pcb-menu.res" char *s = N_("Swap Sides"); # 421 "pcb-menu.res" char *s = N_("T"); # 60 "pcb-menu.res" char *s = N_("Tab"); # 433 "pcb-menu.res" char *s = N_("Temp Arrow OFF"); # 432 "pcb-menu.res" char *s = N_("Temp Arrow ON"); # 180 "pcb-menu.res" char *s = N_("Text"); # 245 "pcb-menu.res" char *s = N_("Text Objects"); # 421 "pcb-menu.res" char *s = N_("Text Tool scale +10 mil"); # 422 "pcb-menu.res" char *s = N_("Text Tool scale -10 mil"); # 267 "pcb-menu.res" char *s = N_("Texts +10 mil"); # 266 "pcb-menu.res" char *s = N_("Texts -10 mil"); # 187 "pcb-menu.res" char *s = N_("Thermal"); # 214 "pcb-menu.res" char *s = N_("Thin draw"); # 215 "pcb-menu.res" char *s = N_("Thin draw poly"); # 170 "pcb-menu.res" char *s = N_("Through-hole"); # 39 "pcb-menu.res" char *s = N_("TinyCAD"); # 393 "pcb-menu.res" char *s = N_("ToggleHideName Object"); # 394 "pcb-menu.res" char *s = N_("ToggleHideName SelectedElement"); # 323 "pcb-menu.res" char *s = N_("Toporouter"); # 138 "pcb-menu.res" char *s = N_("U"); # 429 "pcb-menu.res" char *s = N_("Undo"); # 138 "pcb-menu.res" char *s = N_("Undo last operation"); # 328 "pcb-menu.res" char *s = N_("Unjaggy"); # 150 "pcb-menu.res" char *s = N_("Unselect all"); # 236 "pcb-menu.res" char *s = N_("Unselect all objects"); # 439 "pcb-menu.res" char *s = N_("Up"); # 86 "pcb-menu.res" char *s = N_("V"); # 70 "pcb-menu.res" char *s = N_("Value"); # 177 "pcb-menu.res" char *s = N_("Via"); # 425 "pcb-menu.res" char *s = N_("Via Tool drill +5 mil"); # 426 "pcb-menu.res" char *s = N_("Via Tool drill -5 mil"); # 423 "pcb-menu.res" char *s = N_("Via Tool size +5 mil"); # 424 "pcb-menu.res" char *s = N_("Via Tool size -5 mil"); # 169 "pcb-menu.res" char *s = N_("Via type"); # 329 "pcb-menu.res" char *s = N_("Vianudge"); # 246 "pcb-menu.res" char *s = N_("Vias"); # 273 "pcb-menu.res" char *s = N_("Vias +10 mil"); # 272 "pcb-menu.res" char *s = N_("Vias -10 mil"); # 330 "pcb-menu.res" char *s = N_("Viatrim"); # 428 "pcb-menu.res" char *s = N_("W"); # 171 "pcb-menu.res" char *s = N_("Xtrl-Shift-F"); # 170 "pcb-menu.res" char *s = N_("Xtrl-Shift-P"); # 172 "pcb-menu.res" char *s = N_("Xtrl-Shift-T"); # 334 "pcb-menu.res" char *s = N_("Y"); # 83 "pcb-menu.res" char *s = N_("Z"); # 82 "pcb-menu.res" /* xgettext:no-c-format */ char *s = N_("Zoom In 20%"); # 79 "pcb-menu.res" char *s = N_("Zoom In 2X"); # 86 "pcb-menu.res" char *s = N_("Zoom Max"); # 83 "pcb-menu.res" /* xgettext:no-c-format */ char *s = N_("Zoom Out 20%"); # 85 "pcb-menu.res" char *s = N_("Zoom Out 2X"); # 87 "pcb-menu.res" char *s = N_("Zoom Toggle"); # 90 "pcb-menu.res" char *s = N_("Zoom to 0.01mm/px"); # 92 "pcb-menu.res" char *s = N_("Zoom to 0.05mm/px"); # 89 "pcb-menu.res" char *s = N_("Zoom to 0.1mil/px"); # 94 "pcb-menu.res" char *s = N_("Zoom to 0.1mm/px"); # 95 "pcb-menu.res" char *s = N_("Zoom to 10mil/px"); # 91 "pcb-menu.res" char *s = N_("Zoom to 1mil/px"); # 93 "pcb-menu.res" char *s = N_("Zoom to 2.5mil/px"); # 432 "pcb-menu.res" char *s = N_("["); # 433 "pcb-menu.res" char *s = N_("]"); # 87 "pcb-menu.res" char *s = N_("`"); # 38 "pcb-menu.res" char *s = N_("gschem"); # 98 "pcb-menu.res" char *s = N_("mil"); # 99 "pcb-menu.res" char *s = N_("mm"); # 238 "pcb-menu.res" char *s = N_("unselect all connected objects"); # 237 "pcb-menu.res" char *s = N_("unselect all found objects"); # 214 "pcb-menu.res" char *s = N_("|"); pcb-4.2.2/src/puller.c0000664000076400007640000020306713434555140011470 00000000000000/*! * \file src/puller.c * * \brief . * * \todo Things that need to be fixed before this is "perfect".\n * Add to this list as we find things. * - respect the outline layer. * - don't consider points that are perpendicular to our start_arc. * I.e. when we have busses going around corners, we have a *lot* of * arcs and endpoints that are all in the same direction and all * equally "good", but rounding the arc angles to integers causes * all sorts of tiny differences that result in bumps, reversals, * and other messes. * - Store the X,Y values in our shadow struct so we don't fill up the * undo buffer with all our line reversals. * - at least check the other layers in our layer group. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2006 DJ Delorie * * Copyright (C) 2011 PCB Contributers (See ChangeLog for details) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA * dj@delorie.com */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include #include #include #include #include "create.h" #include "data.h" #include "draw.h" #include "misc.h" #include "move.h" #include "pcb-printf.h" #include "remove.h" #include "rtree.h" #include "strflags.h" #include "undo.h" #include "error.h" #ifdef HAVE_LIBDMALLOC #include #endif #define abort1() fprintf(stderr, "abort at line %d\n", __LINE__), abort() #define TRACE0 0 #define TRACE1 0 /*! Sine of one degree. */ #define SIN1D 0.0174524064372835 static jmp_buf abort_buf; static int multi, line_exact, arc_exact; static LineType *the_line; static ArcType *the_arc; static double arc_dist; /* We canonicalize the arc and line such that the point to be moved is always Point2 for the line, and at start+delta for the arc. */ static Coord x, y; /* the point we're moving */ static Coord cx, cy; /* centerpoint of the arc */ static Coord ex, ey; /* fixed end of the line */ /* 0 is left (-x), 90 is down (+y), 180 is right (+x), 270 is up (-y) */ static Coord within (Coord x1, Coord y1, Coord x2, Coord y2, Coord r) { return Distance (x1, y1, x2, y2) <= r / 2; } static int arc_endpoint_is (ArcType *a, int angle, Coord x, Coord y) { Coord ax = a->X, ay = a->Y; if (angle % 90 == 0) { int ai = (int) (angle / 90) & 3; switch (ai) { case 0: ax -= a->Width; break; case 1: ay += a->Height; break; case 2: ax += a->Width; break; case 3: ay -= a->Height; break; } } else { double rad = angle * M_PI / 180; ax -= a->Width * cos (rad); ay += a->Width * sin (rad); } #if TRACE1 pcb_printf (" - arc endpoint %#mD\n", ax, ay); #endif arc_dist = Distance (ax, ay, x, y); if (arc_exact) return arc_dist < 2; return arc_dist < a->Thickness / 2; } /*! * brief Cross c->u and c->v, return the magnitude. */ static double cross2d (Coord cx, Coord cy, Coord ux, Coord uy, Coord vx, Coord vy) { ux -= cx; uy -= cy; vx -= cx; vy -= cy; return (double)ux * vy - (double)uy * vx; } /*! * \brief Likewise, for dot product. */ static double dot2d (Coord cx, Coord cy, Coord ux, Coord uy, Coord vx, Coord vy) { ux -= cx; uy -= cy; vx -= cx; vy -= cy; return (double)ux * vx + (double)uy * vy; } #if 0 /*! * \brief . * * angle of c->v, relative to c->u, in radians. * Range is -pi..pi. */ static double angle2d (Coord cx, Coord cy, Coord ux, Coord uy, Coord vx, Coord vy) { double cross; double magu, magv, sintheta; #if TRACE1 pcb_printf("angle2d %mD %mD %mD\n", cx, cy, ux, uy, vx, vy); #endif ux -= cx; uy -= cy; vx -= cx; vy -= cy; #if TRACE1 pcb_printf(" = %mD %mD\n", ux, uy, vx, vy); #endif cross = (double)ux * vy - (double)uy * vx; magu = hypot(ux, uy); magv = hypot(vx, vy); sintheta = cross / (magu * magv); #if TRACE1 printf(" = %f / (%f * %f) = %f\n", cross, magu, magv, sintheta); #endif return asin (sintheta); } #endif static int same_sign (double a, double b) { return (a * b >= 0); } static double r2d (double r) { return 180.0 * r / M_PI; } static double d2r (double d) { return M_PI * d / 180.0; } /*! * \brief . * * | a b | * * | c d | */ static double det (double a, double b, double c, double d) { return a * d - b * c; } /*! * \brief . * * The lines are \f$ x_1y_1-x_2y_2 \f$ and \f$ x_3y_3-x_4y_4 \f$. * * \return True if they intersect. */ static int intersection_of_lines (Coord x1, Coord y1, Coord x2, Coord y2, Coord x3, Coord y3, Coord x4, Coord y4, Coord *xr, Coord *yr) { double x, y, d; d = det (x1 - x2, y1 - y2, x3 - x4, y3 - y4); if (!d) return 0; x = (det (det (x1, y1, x2, y2), x1 - x2, det (x3, y3, x4, y4), x3 - x4) / d); y = (det (det (x1, y1, x2, y2), y1 - y2, det (x3, y3, x4, y4), y3 - y4) / d); *xr = (Coord) (x + 0.5); *yr = (Coord) (y + 0.5); return 1; } /*! * \brief Same, for line segments. * * \return True if they intersect. * * For this function, \c xr and \c yr may be \c NULL if you don't need * the values. */ static int intersection_of_linesegs (Coord x1, Coord y1, Coord x2, Coord y2, Coord x3, Coord y3, Coord x4, Coord y4, Coord *xr, Coord *yr) { double x, y, d; d = det (x1 - x2, y1 - y2, x3 - x4, y3 - y4); if (!d) return 0; x = (det (det (x1, y1, x2, y2), x1 - x2, det (x3, y3, x4, y4), x3 - x4) / d); y = (det (det (x1, y1, x2, y2), y1 - y2, det (x3, y3, x4, y4), y3 - y4) / d); if (MIN (x1, x2) > x || x > MAX (x1, x2) || MIN (y1, y2) > y || y > MAX (y1, y2)) return 0; if (MIN (x3, x4) > x || x > MAX (x3, x4) || MIN (y3, y4) > y || y > MAX (y3, y4)) return 0; if (xr) *xr = (Coord) (x + 0.5); if (yr) *yr = (Coord) (y + 0.5); return 1; } /*! * \brief Distance between a line and a point. */ static double dist_lp (Coord x1, Coord y1, Coord x2, Coord y2, Coord px, Coord py) { double den = Distance (x1, y1, x2, y2); double rv = (fabs (((double)x2 - x1) * ((double)y1 - py) - ((double)x1 - px) * ((double)y2 - y1)) / den); #if TRACE1 pcb_printf("dist %#mD-%#mD to %#mD is %f\n", x1, y1, x2, y2, px, py, rv); #endif return rv; } /*! * \brief Distance between a line segment and a point. */ static double dist_lsp (Coord x1, Coord y1, Coord x2, Coord y2, Coord px, Coord py) { double d; if (dot2d (x1, y1, x2, y2, px, py) < 0) return Distance (x1, y1, px, py); if (dot2d (x2, y2, x1, y1, px, py) < 0) return Distance (x2, y2, px, py); d = (fabs (((double)x2 - x1) * ((double)y1 - py) - ((double)x1 - px) * ((double)y2 - y1)) / Distance (x1, y1, x2, y2)); return d; } /* Single Point Puller */ static int line_callback (const BoxType * b, void *cl) { /* LayerType *layer = (LayerType *)cl; */ LineType *l = (LineType *) b; double d1, d2, t; #if TRACE1 pcb_printf ("line %#mD .. %#mD\n", l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y); #endif d1 = Distance (l->Point1.X, l->Point1.Y, x, y); d2 = Distance (l->Point2.X, l->Point2.Y, x, y); if ((d1 < 2 || d2 < 2) && !line_exact) { line_exact = 1; the_line = 0; } t = line_exact ? 2 : l->Thickness / 2; if (d1 < t || d2 < t) { if (the_line) multi = 1; the_line = l; #if TRACE1 printf ("picked, exact %d\n", line_exact); #endif } return 1; } static int arc_callback (const BoxType * b, void *cl) { /* LayerType *layer = (LayerType *) cl; */ ArcType *a = (ArcType *) b; #if TRACE1 pcb_printf ("arc a %#mD r %#mS sa %ld d %ld\n", a->X, a->Y, a->Width, a->StartAngle, a->Delta); #endif if (!arc_endpoint_is (a, a->StartAngle, x, y) && !arc_endpoint_is (a, a->StartAngle + a->Delta, x, y)) return 1; if (arc_dist < 2) { if (!arc_exact) { arc_exact = 1; the_arc = 0; } if (the_arc) multi = 1; the_arc = a; #if TRACE1 printf ("picked, exact %d\n", arc_exact); #endif } else if (!arc_exact) { if (the_arc) multi = 1; the_arc = a; #if TRACE1 printf ("picked, exact %d\n", arc_exact); #endif } return 1; } static int find_pair (Coord Px, Coord Py) { BoxType spot; #if TRACE1 pcb_printf ("\nPuller find_pair at %#mD\n", Px, Py); #endif x = Px; y = Py; multi = 0; line_exact = arc_exact = 0; the_line = 0; the_arc = 0; spot.X1 = x - 1; spot.Y1 = y - 1; spot.X2 = x + 1; spot.Y2 = y + 1; r_search (CURRENT->line_tree, &spot, NULL, line_callback, CURRENT); r_search (CURRENT->arc_tree, &spot, NULL, arc_callback, CURRENT); if (the_line && the_arc && !multi) return 1; x = Px; y = Py; return 0; } static const char puller_syntax[] = "Puller()"; static const char puller_help[] = "Pull an arc-line junction tight."; /* %start-doc actions Puller The @code{Puller()} action is a special-purpose optimization. When invoked while the crosshair is over the junction of an arc and a line, it will adjust the arc's angle and the connecting line's endpoint such that the line intersects the arc at a tangent. In the example below, the left side is ``before'' with the black target marking where to put the crosshair: @center @image{puller,,,Example of how puller works,png} The right side is ``after'' with the black target marking where the arc-line intersection was moved to. %end-doc */ static int Puller (int argc, char **argv, Coord Ux, Coord Uy) { double arc_angle, base_angle; #if TRACE1 double line_angle, rel_angle; #endif double tangent; int new_delta_angle; if (!find_pair (Crosshair.X, Crosshair.Y)) if (!find_pair (Ux, Uy)) return 0; if (within (the_line->Point1.X, the_line->Point1.Y, x, y, the_line->Thickness)) { ex = the_line->Point2.X; ey = the_line->Point2.Y; the_line->Point2.X = the_line->Point1.X; the_line->Point2.Y = the_line->Point1.Y; the_line->Point1.X = ex; the_line->Point1.Y = ey; } else if (!within (the_line->Point2.X, the_line->Point2.Y, x, y, the_line->Thickness)) { #if TRACE1 printf ("Line endpoint not at cursor\n"); #endif return 1; } ex = the_line->Point1.X; ey = the_line->Point1.Y; cx = the_arc->X; cy = the_arc->Y; if (arc_endpoint_is (the_arc, the_arc->StartAngle, x, y)) { ChangeArcAngles (CURRENT, the_arc, the_arc->StartAngle + the_arc->Delta, -the_arc->Delta); } else if (!arc_endpoint_is (the_arc, the_arc->StartAngle + the_arc->Delta, x, y)) { #if TRACE1 printf ("arc not endpoints\n"); #endif return 1; } if (within (cx, cy, ex, ey, the_arc->Width * 2)) { #if TRACE1 printf ("line ends inside arc\n"); #endif return 1; } if (the_arc->Delta > 0) arc_angle = the_arc->StartAngle + the_arc->Delta + 90; else arc_angle = the_arc->StartAngle + the_arc->Delta - 90; base_angle = r2d (atan2 (ey - cy, cx - ex)); tangent = r2d (acos (the_arc->Width / Distance (cx, cy, ex, ey))); #if TRACE1 line_angle = r2d (atan2 (ey - y, x - ex)); rel_angle = line_angle - arc_angle; printf ("arc %g line %g rel %g base %g\n", arc_angle, line_angle, rel_angle, base_angle); printf ("tangent %g\n", tangent); printf ("arc was start %ld end %ld\n", the_arc->StartAngle, the_arc->StartAngle + the_arc->Delta); #endif if (the_arc->Delta > 0) arc_angle = base_angle - tangent; else arc_angle = base_angle + tangent; #if TRACE1 printf ("new end angle %g\n", arc_angle); #endif new_delta_angle = arc_angle - the_arc->StartAngle; if (new_delta_angle > 180) new_delta_angle -= 360; if (new_delta_angle < -180) new_delta_angle += 360; ChangeArcAngles (CURRENT, the_arc, the_arc->StartAngle, new_delta_angle); #if TRACE1 printf ("arc now start %ld end %ld\n", the_arc->StartAngle, the_arc->StartAngle + new_delta_angle); #endif arc_angle = the_arc->StartAngle + the_arc->Delta; x = the_arc->X - the_arc->Width * cos (d2r (arc_angle)) + 0.5; y = the_arc->Y + the_arc->Height * sin (d2r (arc_angle)) + 0.5; MoveObject (LINEPOINT_TYPE, CURRENT, the_line, &(the_line->Point2), x - the_line->Point2.X, y - the_line->Point2.Y); gui->invalidate_all (); IncrementUndoSerialNumber (); return 1; } /* Global Puller */ static const char globalpuller_syntax[] = "GlobalPuller()"; static const char globalpuller_help[] = "Pull all traces tight."; /* %start-doc actions GlobalPuller %end-doc */ /* Ok, here's the deal. We look for the intersection of two traces. The triangle formed by those traces is searched for things we need to avoid. From the other two corners of the triangle, we compute the angle to each obstacle, and remember the ones closest to the start angles. If the two traces hit the same obstacle, we put in the arc and we're done. Else, we bring the traces up to the obstacles and start again. Note that we assume each start point is a tangent to an arc. We start with a radius of zero, but future steps use the arcs we create as we go. For obstacles, we list each round pin, pad, via, and line/arc endpoints as points with a given radius. For each square pin, pad, via, and polygon points, we list each corner with a zero radius. We also list arcs from their centerpoint. We don't currently do anything to move vias, or intersections of three or more traces. In the future, three-way intersections will be handles similarly to two-way - calculate the range of angles valid from each of the three other endpoints, choose the angle closest to making 120 degree angles at the center. For four-way or more intersections, we break them up into multiple three-way intersections. For simplicity, we only do the current layer at this time. We will also edit the lines and arcs in place so that the intersection is always on the second point, and the other ends are always at start+delta for arcs. We also defer intersections which are blocked by other intersections yet to be moved; the idea is to wait until those have been moved so we don't end up with arcs that no longer wrap around things. At a later point, we may choose to pull arced corners in also. You'll see lots of variables of the form "foo_sign" which keep track of which way things are pointing. This is because everything is relative to corners and arcs, not absolute directions. */ static int nloops, npulled; static void status () { Message ("%6d loops, %d pulled \r", nloops, npulled); } /*! * \brief Extra data we need to temporarily attach to all lines and * arcs. */ typedef struct End { /* These point to "multi_next" if there are more than one. */ struct Extra *next; void *pin; unsigned char in_pin:1; unsigned char at_pin:1; unsigned char is_pad:1; unsigned char pending:1; /* set if this may be moved later */ Coord x, y; /* arc endpoint */ /* If not NULL, points to End with pending==1 we're blocked on. */ struct End *waiting_for; } End; typedef struct Extra { End start; End end; unsigned char found:1; unsigned char deleted:1; int type; union { LineType *line; ArcType *arc; } parent; } Extra; static Extra multi_next; static GHashTable *lines; static GHashTable *arcs; static int did_something; static int current_is_top, current_is_bottom; /* If set, these are the pins/pads/vias that this path ends on. */ /* static void *start_pin_pad, *end_pin_pad; */ #if TRACE1 static void trace_paths (); #endif static void mark_line_for_deletion (LineType *); #define LINE2EXTRA(l) ((Extra *)g_hash_table_lookup (lines, l)) #define ARC2EXTRA(a) ((Extra *)g_hash_table_lookup (arcs, a)) #define EXTRA2LINE(e) (e->parent.line) #define EXTRA2ARC(e) (e->parent.arc) #define EXTRA_IS_LINE(e) (e->type == LINE_TYPE) #define EXTRA_IS_ARC(e) (e->type == ARC_TYPE) static void unlink_end (Extra *x, Extra **e) { if (*e) { if ((*e)->start.next == x) { #if TRACE1 printf("%d: unlink_end, was %p\n", __LINE__, (*e)->start.next); #endif (*e)->start.next = &multi_next; } if ((*e)->end.next == x) { #if TRACE1 printf("%d: unlink_end, was %p\n", __LINE__, (*e)->start.next); #endif (*e)->end.next = &multi_next; } } #if TRACE1 printf("%d: unlink_end, was %p\n", __LINE__, (*e)); #endif (*e) = &multi_next; } #if TRACE1 static void clear_found_cb (AnyObjectType *ptr, Extra *extra, void *userdata) { extra->found = 0; } static void clear_found () { g_hash_table_foreach (lines, (GHFunc)clear_found_cb, NULL); g_hash_table_foreach (arcs, (GHFunc)clear_found_cb, NULL); } #endif static void fix_arc_extra (ArcType *a, Extra *e) { #if TRACE1 printf("new arc angles %ld %ld\n", a->StartAngle, a->Delta); #endif e->start.x = a->X - (a->Width * cos (d2r (a->StartAngle)) + 0.5); e->start.y = a->Y + (a->Height * sin (d2r (a->StartAngle)) + 0.5); e->end.x = a->X - (a->Width * cos (d2r (a->StartAngle+a->Delta)) + 0.5); e->end.y = a->Y + (a->Height * sin (d2r (a->StartAngle+a->Delta)) + 0.5); #if TRACE1 pcb_printf("new X,Y is %#mD to %#mD\n", e->start.x, e->start.y, e->end.x, e->end.y); #endif } typedef struct { void *me; Coord x, y; int is_arc; Extra **extra_ptr; } FindPairCallbackStruct; #define NEAR(a,b) ((a) <= (b) + 2 && (a) >= (b) - 2) static int find_pair_line_callback (const BoxType * b, void *cl) { LineType *line = (LineType *) b; #if TRACE1 Extra *e = LINE2EXTRA (line); #endif FindPairCallbackStruct *fpcs = (FindPairCallbackStruct *) cl; if (line == fpcs->me) return 0; #ifdef CHECK_LINE_PT_NEG if (line->Point1.X < 0) abort1(); #endif #if TRACE1 pcb_printf(" - %p line %#mD or %#mD\n", e, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y); #endif if ((NEAR (line->Point1.X, fpcs->x) && NEAR (line->Point1.Y, fpcs->y)) || (NEAR (line->Point2.X, fpcs->x) && NEAR (line->Point2.Y, fpcs->y))) { if (* fpcs->extra_ptr) { #if TRACE1 printf("multiple, was %p\n", *fpcs->extra_ptr); #endif *fpcs->extra_ptr = & multi_next; } else { *fpcs->extra_ptr = LINE2EXTRA (line); #if TRACE1 printf(" - next now %p\n", *fpcs->extra_ptr); #endif } } return 0; } static int find_pair_arc_callback (const BoxType * b, void *cl) { ArcType *arc = (ArcType *) b; Extra *e = ARC2EXTRA (arc); FindPairCallbackStruct *fpcs = (FindPairCallbackStruct *) cl; if (arc == fpcs->me) return 0; #if TRACE1 pcb_printf(" - %p arc %#mD or %#mD\n", e, e->start.x, e->start.y, e->end.x, e->end.y); #endif if ((NEAR (e->start.x, fpcs->x) && NEAR (e->start.y, fpcs->y)) || (NEAR (e->end.x, fpcs->x) && NEAR (e->end.y, fpcs->y))) { if (* fpcs->extra_ptr) { #if TRACE1 printf("multiple, was %p\n", *fpcs->extra_ptr); #endif *fpcs->extra_ptr = & multi_next; } else *fpcs->extra_ptr = e; } return 0; } static void find_pairs_1 (void *me, Extra **e, Coord x, Coord y) { FindPairCallbackStruct fpcs; BoxType b; if (*e) return; fpcs.me = me; fpcs.extra_ptr = e; fpcs.x = x; fpcs.y = y; #if TRACE1 pcb_printf("looking for %#mD\n", x, y); #endif b.X1 = x - 10; b.X2 = x + 10; b.Y1 = y - 10; b.Y2 = y + 10; r_search(CURRENT->line_tree, &b, NULL, find_pair_line_callback, &fpcs); r_search(CURRENT->arc_tree, &b, NULL, find_pair_arc_callback, &fpcs); } static int check_point_in_pin (PinType *pin, Coord x, Coord y, End *e) { int inside_p; Coord t = (PIN_SIZE(pin)+1)/2; if (TEST_FLAG (SQUAREFLAG, pin)) inside_p = (x >= pin->X - t && x <= pin->X + t && y >= pin->Y - t && y <= pin->Y + t); else inside_p = (Distance (pin->X, pin->Y, x, y) <= t); if (inside_p) { e->in_pin = 1; if (pin->X == x && pin->Y == y) e->at_pin = 1; e->pin = pin; return 1; } return 0; } static int find_pair_pinline_callback (const BoxType * b, void *cl) { LineType *line = (LineType *) b; PinType *pin = (PinType *) cl; Extra *e = LINE2EXTRA (line); int hits; #ifdef CHECK_LINE_PT_NEG if (line->Point1.X < 0) abort1(); #endif hits = check_point_in_pin (pin, line->Point1.X, line->Point1.Y, &(e->start)); hits += check_point_in_pin (pin, line->Point2.X, line->Point2.Y, &(e->end)); if (hits) return 0; /* See if the line passes through this pin. */ /*! \todo This assumes round pads, but it's good enough for square * ones for now. */ if (dist_lsp (line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, pin->X, pin->Y) <= PIN_SIZE(pin)/2) { #if TRACE1 pcb_printf("splitting line %#mD-%#mD because it passes through pin %#mD r%d\n", line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, pin->X, pin->Y, PIN_SIZE(pin)/2); #endif unlink_end (e, &e->start.next); unlink_end (e, &e->end.next); } return 0; } static int find_pair_pinarc_callback (const BoxType * b, void *cl) { ArcType *arc = (ArcType *) b; PinType *pin = (PinType *) cl; Extra *e = ARC2EXTRA (arc); int hits; hits = check_point_in_pin (pin, e->start.x, e->start.y, &(e->start)); hits += check_point_in_pin (pin, e->end.x, e->end.y, &(e->end)); return 0; } static int check_point_in_pad (PadType *pad, Coord x, Coord y, End *e) { int inside_p; Coord t; pcb_printf("pad %#mD - %#mD t %#mS vs %#mD\n", pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y, pad->Thickness, x, y); t = (pad->Thickness+1)/2; if (TEST_FLAG (SQUAREFLAG, pad)) { inside_p = (x >= MIN (pad->Point1.X - t, pad->Point2.X - t) && x <= MAX (pad->Point1.X + t, pad->Point2.X + t) && y >= MIN (pad->Point1.Y - t, pad->Point2.Y - t) && y <= MAX (pad->Point1.Y + t, pad->Point2.Y + t)); printf(" - inside_p = %d\n", inside_p); } else { if (pad->Point1.X == pad->Point2.X) { inside_p = (x >= pad->Point1.X - t && x <= pad->Point1.X + t && y >= MIN (pad->Point1.Y, pad->Point2.Y) && y <= MAX (pad->Point1.Y, pad->Point2.Y)); } else { inside_p = (x >= MIN (pad->Point1.X, pad->Point2.X) && x <= MAX (pad->Point1.X, pad->Point2.X) && y >= pad->Point1.Y - t && y <= pad->Point1.Y + t); } if (!inside_p) { if (Distance (pad->Point1.X, pad->Point1.Y, x, y) <= t || Distance (pad->Point2.X, pad->Point2.Y, x, y) <= t) inside_p = 1; } } if (inside_p) { e->in_pin = 1; if (pad->Point1.X == x && pad->Point1.Y == y) e->at_pin = 1; if (pad->Point2.X == x && pad->Point2.Y == y) e->at_pin = 1; e->pin = pad; e->is_pad = 1; return 1; } return 0; } static int find_pair_padline_callback (const BoxType * b, void *cl) { LineType *line = (LineType *) b; PadType *pad = (PadType *) cl; Extra *e = LINE2EXTRA (line); int hits; double t; int intersect; double p1_d, p2_d; if (TEST_FLAG (ONSOLDERFLAG, pad)) { if (!current_is_bottom) return 0; } else { if (!current_is_top) return 0; } #ifdef CHECK_LINE_PT_NEG if (line->Point1.X < 0) abort1(); #endif hits = check_point_in_pad (pad, line->Point1.X, line->Point1.Y, &(e->start)); hits += check_point_in_pad (pad, line->Point2.X, line->Point2.Y, &(e->end)); if (hits) return 0; /* Ok, something strange. The line intersects our space, but doesn't end in our space. See if it just passes through us, and mark it anyway. */ t = (pad->Thickness + 1)/2; /*! \todo This is for round pads. Good enough for now, but add * square pad support later. */ intersect = intersection_of_linesegs (pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, NULL, NULL); p1_d = dist_lsp(line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, pad->Point1.X, pad->Point1.Y); p2_d = dist_lsp(line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, pad->Point2.X, pad->Point2.Y); if (intersect || p1_d < t || p2_d < t) { /* It does. */ /*! \todo We should split the line. */ #if TRACE1 pcb_printf("splitting line %#mD-%#mD because it passes through pad %#mD-%#mD r %#mS\n", line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y, pad->Point1.X, pad->Point1.Y, pad->Point2.X, pad->Point2.Y, pad->Thickness/2); #endif unlink_end (e, &e->start.next); unlink_end (e, &e->end.next); } return 0; } static int find_pair_padarc_callback (const BoxType * b, void *cl) { ArcType *arc = (ArcType *) b; PadType *pad = (PadType *) cl; Extra *e = ARC2EXTRA (arc); int hits; if (TEST_FLAG (ONSOLDERFLAG, pad)) { if (!current_is_bottom) return 0; } else { if (!current_is_top) return 0; } hits = check_point_in_pad (pad, e->start.x, e->start.y, &(e->start)); hits += check_point_in_pad (pad, e->end.x, e->end.y, &(e->end)); return 0; } static void null_multi_next_ends (AnyObjectType *ptr, Extra *extra, void *userdata) { if (extra->start.next == &multi_next) extra->start.next = NULL; if (extra->end.next == &multi_next) extra->end.next = NULL; } static Extra * new_line_extra (LineType *line) { Extra *extra = g_slice_new0 (Extra); g_hash_table_insert (lines, line, extra); extra->parent.line = line; extra->type = LINE_TYPE; return extra; } static Extra * new_arc_extra (ArcType *arc) { Extra *extra = g_slice_new0 (Extra); g_hash_table_insert (arcs, arc, extra); extra->parent.arc = arc; extra->type = ARC_TYPE; return extra; } static void find_pairs () { ARC_LOOP (CURRENT); { Extra *e = new_arc_extra (arc); fix_arc_extra (arc, e); } END_LOOP; LINE_LOOP (CURRENT); { new_line_extra (line); } END_LOOP; LINE_LOOP (CURRENT); { Extra *e = LINE2EXTRA (line); if (line->Point1.X >= 0) { find_pairs_1 (line, & e->start.next, line->Point1.X, line->Point1.Y); find_pairs_1 (line, & e->end.next, line->Point2.X, line->Point2.Y); } } END_LOOP; ARC_LOOP (CURRENT); { Extra *e = ARC2EXTRA (arc); if (!e->deleted) { find_pairs_1 (arc, & e->start.next, e->start.x, e->start.y); find_pairs_1 (arc, & e->end.next, e->end.x, e->end.y); } } END_LOOP; ALLPIN_LOOP (PCB->Data); { BoxType box; box.X1 = pin->X - PIN_SIZE(pin)/2; box.Y1 = pin->Y - PIN_SIZE(pin)/2; box.X2 = pin->X + PIN_SIZE(pin)/2; box.Y2 = pin->Y + PIN_SIZE(pin)/2; r_search (CURRENT->line_tree, &box, NULL, find_pair_pinline_callback, pin); r_search (CURRENT->arc_tree, &box, NULL, find_pair_pinarc_callback, pin); } ENDALL_LOOP; VIA_LOOP (PCB->Data); { BoxType box; box.X1 = via->X - PIN_SIZE(via)/2; box.Y1 = via->Y - PIN_SIZE(via)/2; box.X2 = via->X + PIN_SIZE(via)/2; box.Y2 = via->Y + PIN_SIZE(via)/2; r_search (CURRENT->line_tree, &box, NULL, find_pair_pinline_callback, via); r_search (CURRENT->arc_tree, &box, NULL, find_pair_pinarc_callback, via); } END_LOOP; ALLPAD_LOOP (PCB->Data); { BoxType box; box.X1 = MIN(pad->Point1.X, pad->Point2.X) - pad->Thickness/2; box.Y1 = MIN(pad->Point1.Y, pad->Point2.Y) - pad->Thickness/2; box.X2 = MAX(pad->Point1.X, pad->Point2.X) + pad->Thickness/2; box.Y2 = MAX(pad->Point1.Y, pad->Point2.Y) + pad->Thickness/2; r_search (CURRENT->line_tree, &box, NULL, find_pair_padline_callback, pad); r_search (CURRENT->arc_tree, &box, NULL, find_pair_padarc_callback, pad); } ENDALL_LOOP; g_hash_table_foreach (lines, (GHFunc)null_multi_next_ends, NULL); g_hash_table_foreach (arcs, (GHFunc)null_multi_next_ends, NULL); } #define PROP_NEXT(e,n,f) \ if (f->next->start.next == e) { \ e = f->next; \ n = & e->start; \ f = & e->end; \ } else { \ e = f->next; \ n = & e->end; \ f = & e->start; } static void propogate_ends_at (Extra *e, End *near, End *far) { while (far->in_pin && far->pin == near->pin) { far->in_pin = 0; if (!far->next) return; PROP_NEXT (e, near, far); near->in_pin = 0; } } static void propogate_end_pin (Extra *e, End *near, End *far) { void *pinpad = near->pin; int ispad = near->is_pad; while (far->next) { PROP_NEXT (e, near, far); if (near->pin == pinpad) break; near->pin = pinpad; near->is_pad = ispad; } } static void propogate_end_step1_cb (AnyObjectType *ptr, Extra *extra, void *userdata) { if (extra->start.next != NULL && extra->start.next == extra->end.next) { extra->end.next = NULL; mark_line_for_deletion ((LineType *)ptr); } if (extra->start.at_pin) propogate_ends_at (extra, &extra->start, &extra->end); if (extra->end.at_pin) propogate_ends_at (extra, &extra->end, &extra->start); } static void propogate_end_step2_cb (AnyObjectType *ptr, Extra *extra, void *userdata) { if (extra->start.in_pin) { #if TRACE1 printf("MULTI at %d: was %p\n", __LINE__, extra->start.next); #endif extra->start.next = NULL; } if (extra->end.in_pin) { #if TRACE1 printf("MULTI at %d: was %p\n", __LINE__, extra->end.next); #endif extra->end.next = NULL; } } static void propogate_end_step3_cb (AnyObjectType *ptr, Extra *extra, void *userdata) { if (extra->start.next) propogate_end_pin (extra, &extra->end, &extra->start); if (extra->end.next) propogate_end_pin (extra, &extra->start, &extra->end); } static void propogate_ends () { /* First, shut of "in pin" when we have an "at pin". We also clean up zero-length lines. */ g_hash_table_foreach (lines, (GHFunc)propogate_end_step1_cb, NULL); /* Now end all paths at pins/pads. */ g_hash_table_foreach (lines, (GHFunc)propogate_end_step2_cb, NULL); /* Now, propogate the pin/pad/vias along paths. */ g_hash_table_foreach (lines, (GHFunc)propogate_end_step3_cb, NULL); } static Extra *last_pextra = 0; static void print_extra (Extra *e, Extra *prev) { int which = 0; if (e->start.next == last_pextra) which = 1; else if (e->end.next == last_pextra) which = 2; switch (which) { case 0: printf("%10p %10p %10p :", e, e->start.next, e->end.next); break; case 1: printf("%10p \033[33m%10p\033[0m %10p :", e, e->start.next, e->end.next); break; case 2: printf("%10p %10p \033[33m%10p\033[0m :", e, e->start.next, e->end.next); break; } last_pextra = e; printf(" %c%c", e->deleted ? 'd' : '-', e->found ? 'f' : '-'); printf(" s:%s%s%s%s", e->start.in_pin ? "I" : "-", e->start.at_pin ? "A" : "-", e->start.is_pad ? "P" : "-", e->start.pending ? "p" : "-"); printf(" e:%s%s%s%s ", e->end.in_pin ? "I" : "-", e->end.at_pin ? "A" : "-", e->end.is_pad ? "P" : "-", e->end.pending ? "p" : "-"); if (EXTRA_IS_LINE (e)) { LineType *line = EXTRA2LINE (e); pcb_printf(" %p L %#mD-%#mD", line, line->Point1.X, line->Point1.Y, line->Point2.X, line->Point2.Y); printf(" %s %p %s %p\n", e->start.is_pad ? "pad" : "pin", e->start.pin, e->end.is_pad ? "pad" : "pin", e->end.pin); } else if (EXTRA_IS_ARC (e)) { ArcType *arc = EXTRA2ARC (e); pcb_printf(" %p A %#mD-%#mD", arc, e->start.x, e->start.y, e->end.x, e->end.y); pcb_printf(" at %#mD ang %ld,%ld\n", arc->X, arc->Y, arc->StartAngle, arc->Delta); } else if (e == &multi_next) { printf("-- Multi-next\n"); } else { printf("-- Unknown extra: %p\n", e); } } #if TRACE1 static void trace_path (Extra *e) { Extra *prev = 0; if ((e->start.next && e->end.next) || (!e->start.next && !e->end.next)) return; if (e->found) return; printf("- path -\n"); last_pextra = 0; while (e) { e->found = 1; print_extra (e, prev); if (e->start.next == prev) { prev = e; e = e->end.next; } else { prev = e; e = e->start.next; } } } static void trace_paths () { Extra *e; clear_found (); LINE_LOOP (CURRENT); { e = LINE2EXTRA (line); trace_path (e); } END_LOOP; ARC_LOOP (CURRENT); { e = ARC2EXTRA (arc); trace_path (e); } END_LOOP; } #endif static void reverse_line (LineType *line) { Extra *e = LINE2EXTRA (line); Coord x, y; End etmp; x = line->Point1.X; y = line->Point1.Y; #if 1 MoveObject (LINEPOINT_TYPE, CURRENT, line, &(line->Point1), line->Point2.X - line->Point1.X, line->Point2.Y - line->Point1.Y); MoveObject (LINEPOINT_TYPE, CURRENT, line, &(line->Point2), x - line->Point2.X, y - line->Point2.Y); #else /* In theory, we should be using the above so that undo works. */ line->Point1.X = line->Point2.X; line->Point1.Y = line->Point2.Y; line->Point2.X = x; line->Point2.Y = y; #endif memcpy (&etmp, &e->start, sizeof (End)); memcpy (&e->start, &e->end, sizeof (End)); memcpy (&e->end, &etmp, sizeof (End)); } static void reverse_arc (ArcType *arc) { Extra *e = ARC2EXTRA (arc); End etmp; #if 1 ChangeArcAngles (CURRENT, arc, arc->StartAngle + arc->Delta, -arc->Delta); #else /* Likewise, see above. */ arc->StartAngle += arc->Delta; arc->Delta *= -1; #endif memcpy (&etmp, &e->start, sizeof (End)); memcpy (&e->start, &e->end, sizeof (End)); memcpy (&e->end, &etmp, sizeof (End)); } static void expand_box (BoxType *b, Coord x, Coord y, Coord t) { b->X1 = MIN (b->X1, x-t); b->X2 = MAX (b->X2, x+t); b->Y1 = MIN (b->Y1, y-t); b->Y2 = MAX (b->Y2, y+t); } /* ---------------------------------------------------------------------- */ /* These are the state variables for the intersection we're currently working on. */ /* what we're working with */ static ArcType *start_arc; static LineType *start_line; static LineType *end_line; static ArcType *end_arc; static Extra *start_extra, *end_extra; static Extra *sarc_extra, *earc_extra; static void *start_pinpad, *end_pinpad; static Coord thickness; /* Pre-computed values. Note that all values are computed according to CARTESIAN coordinates, not PCB coordinates. Do an up-down board flip before wrapping your brain around the math. */ /* se_sign is positive when you make a right turn going from start to end. */ /* sa_sign is positive when start's arc is on the same side of start as end. */ /* ea_sign is positive when end's arc is on the same side of end as start. */ /* sa_sign and ea_sign may be zero if there's no arc. */ static double se_sign, sa_sign, ea_sign; static double best_angle, start_angle, end_dist; /* arc radii are positive when they're on the same side as the things we're interested in. */ static Coord sa_r, ea_r; static Coord sa_x, sa_y; /* start "arc" point */ /* what we've found so far */ static Coord fx, fy, fr; static int fp; static End *fp_end; static double fa; /* relative angle */ #define gp_point(x,y,t,e) gp_point_2(x,y,t,e,0,0,__FUNCTION__) static int gp_point_force (Coord x, Coord y, Coord t, End *e, int esa, int eda, int force, const char *name) { double r, a, d; Coord scx, scy, sr; double base_angle, rel_angle, point_angle; #if TRACE1 pcb_printf("\033[34mgp_point_force %#mD %#mS via %s\033[0m\n", x, y, t, name); #endif if (start_arc) { scx = start_arc->X; scy = start_arc->Y; sr = start_arc->Width; } else { scx = start_line->Point1.X; scy = start_line->Point1.Y; sr = 0; } r = t + thickness; /* See if the point is inside our start arc. */ d = Distance (scx, scy, x, y); #if TRACE1 pcb_printf("%f = dist #mD to %#mD\n", d, scx, scy, x, y); pcb_printf("sr %#mS r %f d %f\n", sr, r, d); #endif if (d < sr - r) { #if TRACE1 printf("inside start arc, %f < %f\n", d, sr-r); #endif return 0; } if (sr == 0 && d < r) { #if TRACE1 printf("start is inside arc, %f < %f\n", d, r); #endif return 0; } /* Now for the same tricky math we needed for the single puller. sr and r are the radii for the two points scx,scy and x,y. */ /* angle between points (NOT pcb arc angles) */ base_angle = atan2 (y - scy, x - scx); #if TRACE1 pcb_printf("%.1f = atan2 (%#mS-%#mS = %#mS, %#mS-%#mS = %#mS)\n", r2d(base_angle), y, scy, y-scy, x, scx, x-scx); #endif if ((sa_sign * sr - r) / d > 1 || (sa_sign * sr - r) / d < -1) return 0; /* Angle of tangent, relative to the angle between point centers. */ rel_angle = se_sign * asin ((sa_sign * sr - r) / d); #if TRACE1 printf("%.1f = %d * asin ((%d * %d - %f) / %f)\n", r2d(rel_angle), (int)se_sign, (int)sa_sign, sr, r, d); #endif /* Absolute angle of tangent. */ point_angle = base_angle + rel_angle; #if TRACE1 printf("base angle %.1f rel_angle %.1f point_angle %.1f\n", r2d(base_angle), r2d(rel_angle), r2d(point_angle)); #endif if (eda) { /* Check arc angles */ double pa = point_angle; double sa = d2r(180-esa); double da = d2r(-eda); if (da < 0) { sa = sa + da; da = -da; } pa -= se_sign * M_PI/2; while (sa+da < pa) sa += M_PI*2; while (sa > pa) sa -= M_PI*2; if (sa+da < pa) { #if TRACE1 printf("arc doesn't apply: sa %.1f da %.1f pa %.1f\n", r2d(sa), r2d(da), r2d(pa)); #endif return 0; } } a = point_angle - start_angle; while (a > M_PI) a -= M_PI*2; while (a < -M_PI) a += M_PI*2; #if TRACE1 printf(" - angle relative to S-E baseline is %.1f\n", r2d(a)); #endif if (!force && a * se_sign < -0.007) { double new_r; #if TRACE1 printf("skipping, would increase angle (%f * %f)\n", a, se_sign); #endif new_r = dist_lp (start_line->Point1.X, start_line->Point1.Y, start_line->Point2.X, start_line->Point2.Y, x, y); #if TRACE1 pcb_printf("point %#mD dist %#mS vs thickness %#mS\n", x, y, new_r, thickness); #endif new_r -= thickness; new_r = (int)new_r - 1; #if TRACE1 pcb_printf(" - new thickness %f old %#mS\n", new_r, t); #endif if (new_r < t) gp_point_force (x, y, new_r, e, esa, eda, 1, __FUNCTION__); return 0; } #if TRACE1 printf("%f * %f < %f * %f ?\n", a, se_sign, best_angle, se_sign); #endif if (a * se_sign == best_angle * se_sign) { double old_d = Distance (start_line->Point1.X, start_line->Point1.Y, fx, fy); double new_d = Distance (start_line->Point1.X, start_line->Point1.Y, x, y); if (new_d > old_d) { best_angle = a; fx = x; fy = y; fr = r; fa = a; fp = e ? e->pending : 0; fp_end = e; } } else if (a * se_sign < best_angle * se_sign) { best_angle = a; fx = x; fy = y; fr = r; fa = a; fp = e ? e->pending : 0; fp_end = e; } return 1; } static int gp_point_2 (Coord x, Coord y, Coord t, End *e, int esa, int eda, const char *func) { double sc, ec; double sd, ed; if (x == sa_x && y ==sa_y) return 0; #if TRACE1 pcb_printf("\033[34mgp_point %#mD %#mS via %s\033[0m\n", x, y, t, func); #endif /* There are two regions we care about. For points inside our triangle, we check the crosses against start_line and end_line to make sure the point is "inside" the triangle. For points on the other side of the s-e line of the triangle, we check the dots to make sure it's between our endpoints. */ /* See what side of the s-e line we're on */ sc = cross2d (start_line->Point1.X, start_line->Point1.Y, end_line->Point2.X, end_line->Point2.Y, x, y); #if TRACE1 printf("s-e cross = %f\n", sc); #endif if (t >= 0) { if (same_sign (sc, se_sign)) { /* Outside, check dots. */ /* Ok, is it "in front of" our vectors? */ sd = dot2d (start_line->Point1.X, start_line->Point1.Y, end_line->Point2.X, end_line->Point2.Y, x, y); #if TRACE1 printf("sd = %f\n", sd); #endif if (sd <= 0) return 0; ed = dot2d (end_line->Point2.X, end_line->Point2.Y, start_line->Point1.X, start_line->Point1.Y, x, y); #if TRACE1 printf("ed = %f\n", ed); #endif if (ed <= 0) return 0; sd = dist_lp (start_line->Point1.X, start_line->Point1.Y, end_line->Point2.X, end_line->Point2.Y, x, y); if (sd > t + thickness) return 0; } else { /* Inside, check crosses. */ /* First off, is it on the correct side of the start line? */ sc = cross2d (start_line->Point1.X, start_line->Point1.Y, start_line->Point2.X, start_line->Point2.Y, x, y); #if TRACE1 printf("sc = %f\n", sc); #endif if (! same_sign (sc, se_sign)) return 0; /* Ok, is it on the correct side of the end line? */ ec = cross2d (end_line->Point1.X, end_line->Point1.Y, end_line->Point2.X, end_line->Point2.Y, x, y); #if TRACE1 printf("ec = %f\n", ec); #endif if (! same_sign (ec, se_sign)) return 0; } } #if TRACE1 printf("in range!\n"); #endif return gp_point_force (x, y, t, e, esa, eda, 0, func); } static int gp_line_cb (const BoxType *b, void *cb) { const LineType *l = (LineType *) b; Extra *e = LINE2EXTRA(l); if (l == start_line || l == end_line) return 0; if (e->deleted) return 0; #ifdef CHECK_LINE_PT_NEG if (l->Point1.X < 0) abort1(); #endif if (! e->start.next || ! EXTRA_IS_ARC (e->start.next)) gp_point (l->Point1.X, l->Point1.Y, l->Thickness/2, &e->start); if (! e->end.next || ! EXTRA_IS_ARC (e->end.next)) gp_point (l->Point2.X, l->Point2.Y, l->Thickness/2, &e->end); return 0; } static int gp_arc_cb (const BoxType *b, void *cb) { const ArcType *a = (ArcType *) b; Extra *e = ARC2EXTRA(a); if (a == start_arc || a == end_arc) return 0; if (e->deleted) return 0; gp_point_2 (a->X, a->Y, a->Width + a->Thickness/2, 0, a->StartAngle, a->Delta, __FUNCTION__); if (start_arc && a->X == start_arc->X && a->Y == start_arc->Y) return 0; if (end_arc && a->X != end_arc->X && a->Y != end_arc->Y) return 0; if (e->start.next || e->end.next) return 0; gp_point (e->start.x, e->start.y, a->Thickness/2, 0); gp_point (e->end.x, e->end.y, a->Thickness/2, 0); return 0; } static int gp_text_cb (const BoxType *b, void *cb) { const TextType *t = (TextType *) b; /* FIXME: drop in the actual text-line endpoints later. */ gp_point (t->BoundingBox.X1, t->BoundingBox.Y1, 0, 0); gp_point (t->BoundingBox.X1, t->BoundingBox.Y2, 0, 0); gp_point (t->BoundingBox.X2, t->BoundingBox.Y2, 0, 0); gp_point (t->BoundingBox.X2, t->BoundingBox.Y1, 0, 0); return 0; } static int gp_poly_cb (const BoxType *b, void *cb) { int i; const PolygonType *p = (PolygonType *) b; for (i=0; iPointN; i++) gp_point (p->Points[i].X, p->Points[i].Y, 0, 0); return 0; } static int gp_pin_cb (const BoxType *b, void *cb) { const PinType *p = (PinType *) b; Coord t2 = (PIN_SIZE(p)+1)/2; if (p == start_pinpad || p == end_pinpad) return 0; /*! \todo We lump octagonal pins in with square; safe, but not * optimal. */ if (TEST_FLAG (SQUAREFLAG, p) || TEST_FLAG (OCTAGONFLAG, p)) { gp_point (p->X - t2, p->Y - t2, 0, 0); gp_point (p->X - t2, p->Y + t2, 0, 0); gp_point (p->X + t2, p->Y + t2, 0, 0); gp_point (p->X + t2, p->Y - t2, 0, 0); } else { gp_point (p->X, p->Y, t2, 0); } return 0; } static int gp_pad_cb (const BoxType *b, void *cb) { const PadType *p = (PadType *) b; Coord t2 = (p->Thickness+1)/2; if (p == start_pinpad || p == end_pinpad) return 0; if (TEST_FLAG (ONSOLDERFLAG, p)) { if (!current_is_bottom) return 0; } else { if (!current_is_top) return 0; } /*! \todo We lump octagonal pads in with square; safe, but not optimal. I don't think we even support octagonal pads. */ if (TEST_FLAG (SQUAREFLAG, p) || TEST_FLAG (OCTAGONFLAG, p)) { if (p->Point1.X == p->Point2.X) { Coord y1 = MIN (p->Point1.Y, p->Point2.Y) - t2; Coord y2 = MAX (p->Point1.Y, p->Point2.Y) + t2; gp_point (p->Point1.X - t2, y1, 0, 0); gp_point (p->Point1.X - t2, y2, 0, 0); gp_point (p->Point1.X + t2, y1, 0, 0); gp_point (p->Point1.X + t2, y2, 0, 0); } else { Coord x1 = MIN (p->Point1.X, p->Point2.X) - t2; Coord x2 = MAX (p->Point1.X, p->Point2.X) + t2; gp_point (x1, p->Point1.Y - t2, 0, 0); gp_point (x2, p->Point1.Y - t2, 0, 0); gp_point (x1, p->Point1.Y + t2, 0, 0); gp_point (x2, p->Point1.Y + t2, 0, 0); } } else { gp_point (p->Point1.X, p->Point1.Y, t2, 0); gp_point (p->Point2.X, p->Point2.Y, t2, 0); } return 0; } static LineType * create_line (LineType *sample, Coord x1, Coord y1, Coord x2, Coord y2) { #if TRACE1 Extra *e; pcb_printf("create_line from %#mD to %#mD\n", x1, y1, x2, y2); #endif LineType *line = CreateNewLineOnLayer (CURRENT, x1, y1, x2, y2, sample->Thickness, sample->Clearance, sample->Flags); AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line); #if TRACE1 e = #endif new_line_extra (line); #if TRACE1 printf(" - line extra is %p\n", e); #endif return line; } static ArcType * create_arc (LineType *sample, Coord x, Coord y, Coord r, Coord sa, Coord da) { Extra *e; ArcType *arc; if (r % 100 == 1) r--; if (r % 100 == 99) r++; #if TRACE1 pcb_printf("create_arc at %#mD r %#mS sa %d delta %d\n", x, y, r, sa, da); #endif arc = CreateNewArcOnLayer (CURRENT, x, y, r, r, sa, da, sample->Thickness, sample->Clearance, sample->Flags); if (arc == 0) { arc = CreateNewArcOnLayer (CURRENT, x, y, r, r, sa, da*2, sample->Thickness, sample->Clearance, sample->Flags); } AddObjectToCreateUndoList (ARC_TYPE, CURRENT, arc, arc); if (!arc) longjmp (abort_buf, 1); e = new_arc_extra (arc); #if TRACE1 printf(" - arc extra is %p\n", e); #endif fix_arc_extra (arc, e); return arc; } static void unlink_extras (Extra *e) { #if TRACE1 fprintf(stderr, "unlink %p\n", e); print_extra(e,0); #endif if (e->start.next) { #if TRACE1 print_extra(e->start.next, 0); #endif if (e->start.next->start.next == e) { #if TRACE1 fprintf(stderr, " - %p->start points to me\n", e->start.next); #endif e->start.next->start.next = e->end.next; } else if (e->start.next->end.next == e) { #if TRACE1 fprintf(stderr, " - %p->end points to me\n", e->start.next); #endif e->start.next->end.next = e->end.next; } else { fprintf(stderr, " - %p doesn't point to me!\n", e->start.next); abort(); } } if (e->end.next) { #if TRACE1 print_extra(e->end.next, 0); #endif if (e->end.next->start.next == e) { #if TRACE1 fprintf(stderr, " - %p->end points to me\n", e->end.next); #endif e->end.next->start.next = e->start.next; } else if (e->end.next->end.next == e) { #if TRACE1 fprintf(stderr, " - %p->end points to me\n", e->end.next); #endif e->end.next->end.next = e->start.next; } else { fprintf(stderr, " - %p doesn't point to me!\n", e->end.next); abort(); } } e->start.next = e->end.next = 0; } static void mark_line_for_deletion (LineType *l) { Extra *e = LINE2EXTRA(l); if (e->deleted) { fprintf(stderr, "double delete?\n"); abort(); } e->deleted = 1; unlink_extras (e); #if TRACE1 pcb_printf("Marked line %p for deletion %#mD to %#mD\n", e, l->Point1.X, l->Point1.Y, l->Point2.X, l->Point2.Y); #endif #if 0 if (l->Point1.X < 0) { fprintf(stderr, "double neg move?\n"); abort(); } MoveObject (LINEPOINT_TYPE, CURRENT, l, &(l->Point1), -1 - l->Point1.X, -1 - l->Point1.Y); MoveObject (LINEPOINT_TYPE, CURRENT, l, &(l->Point2), -1 - l->Point2.X, -1 - l->Point2.Y); #endif } static void mark_arc_for_deletion (ArcType *a) { Extra *e = ARC2EXTRA(a); e->deleted = 1; unlink_extras (e); #if TRACE1 printf("Marked arc %p for deletion %ld < %ld\n", e, a->StartAngle, a->Delta); #endif } /*! * \brief . * * Given a starting line, which may be attached to an arc, and which * intersects with an ending line, which also may be attached to an * arc, maybe pull them.\n * We assume start_line is attached to the arc via Point1, and attached * to the end line via Point2.\n * Likewise, we make end_line attach to the start_line via Point1 and * the arc via Point 2.\n * We also make the arcs attach on the Delta end, not the Start end.\n * Here's a picture: *
     S            S+D  P1            P2   P1          P2  S+D          S
   *--- start_arc ---*--- start_line ---*--- end_line ---*--- end_arc ---*
     S             E   S              E   S            E   E           S
 * 
*/ static void maybe_pull_1 (LineType *line) { BoxType box; /* Line half-thicknesses, including line space */ Coord ex, ey; LineType *new_line; Extra *new_lextra; ArcType *new_arc; Extra *new_aextra; double abs_angle; start_line = line; start_extra = LINE2EXTRA (start_line); end_extra = start_extra->end.next; end_line = EXTRA2LINE (end_extra); if (end_extra->deleted) { start_extra->end.pending = 0; return; } if (end_extra->end.next == start_extra) reverse_line (end_line); if (start_extra->start.next && EXTRA_IS_ARC (start_extra->start.next)) { sarc_extra = start_extra->start.next; start_arc = EXTRA2ARC (sarc_extra); if (sarc_extra->start.next == start_extra) reverse_arc (start_arc); } else { start_arc = 0; sarc_extra = 0; } if (end_extra->end.next && EXTRA_IS_ARC (end_extra->end.next)) { earc_extra = end_extra->end.next; end_arc = EXTRA2ARC (earc_extra); if (earc_extra->start.next == end_extra) reverse_arc (end_arc); } else { end_arc = 0; earc_extra = 0; } #if TRACE1 printf("maybe_pull_1 %p %p %p %p\n", sarc_extra, start_extra, end_extra, earc_extra); if (sarc_extra) print_extra(sarc_extra,0); print_extra(start_extra,0); print_extra(end_extra,0); if (earc_extra) print_extra(earc_extra,0); if (start_extra->deleted || end_extra->deleted || (sarc_extra && sarc_extra->deleted) || (earc_extra && earc_extra->deleted)) { printf(" one is deleted?\n"); fflush(stdout); abort(); } #endif if (!start_extra->end.pending) return; #if 0 if (start_extra->end.waiting_for && start_extra->end.waiting_for->pending) return; #endif if (start_line->Thickness != end_line->Thickness) return; thickness = (start_line->Thickness + 1)/2 + PCB->Bloat; /* At this point, our expectations are all met. */ box.X1 = start_line->Point1.X - thickness; box.X2 = start_line->Point1.X + thickness; box.Y1 = start_line->Point1.Y - thickness; box.Y2 = start_line->Point1.Y + thickness; expand_box (&box, start_line->Point2.X, start_line->Point2.Y, thickness); expand_box (&box, end_line->Point2.X, end_line->Point2.Y, thickness); if (start_arc) expand_box (&box, sarc_extra->start.x, sarc_extra->start.y, start_arc->Thickness/2); if (end_arc) expand_box (&box, earc_extra->start.x, earc_extra->start.y, end_arc->Thickness/2); se_sign = copysign (1, cross2d (start_line->Point1.X, start_line->Point1.Y, start_line->Point2.X, start_line->Point2.Y, end_line->Point2.X, end_line->Point2.Y)); best_angle = se_sign * M_PI; if (start_arc) { sa_sign = copysign (1, -start_arc->Delta); sa_sign *= se_sign; } else sa_sign = 0; if (end_arc) { ea_sign = copysign (1, -end_arc->Delta); ea_sign *= -se_sign; } else ea_sign = 0; start_angle = atan2 (start_line->Point2.Y - start_line->Point1.Y, start_line->Point2.X - start_line->Point1.X); #if TRACE1 printf("se_sign %f sa_sign %f ea_sign %f best_angle %f start_angle %f\n", se_sign, sa_sign, ea_sign, r2d (best_angle), r2d(start_angle)); #endif if (start_arc) { sa_x = start_arc->X; sa_y = start_arc->Y; if (same_sign (start_arc->Delta, se_sign)) sa_r = - start_arc->Width; else sa_r = start_arc->Width; } else { sa_x = start_line->Point1.X; sa_y = start_line->Point1.Y; sa_r = 0; } if (end_arc) { if (ea_sign < 0) ea_r = end_arc->Width; else ea_r = - end_arc->Width; } else ea_r = 0; #if TRACE1 trace_path (sarc_extra ? sarc_extra : start_extra); #endif if (end_arc) { gp_point_force (end_arc->X, end_arc->Y, -ea_r-thickness, 0, 0, 0, 1, "end arc"); ex = end_arc->X; ey = end_arc->Y; } else { gp_point_force (end_line->Point2.X, end_line->Point2.Y, -thickness, 0, 0, 0, 1, "end arc"); ex = end_line->Point2.X; ey = end_line->Point2.Y; } fx = ex; fy = ey; if (fx < 0) { pcb_fprintf(stderr, "end line corrupt? f is %#mD\n", fx, fy); print_extra (end_extra, 0); if (earc_extra) print_extra(earc_extra, 0); abort(); } end_dist = Distance (end_line->Point1.X, end_line->Point1.Y, end_line->Point2.X, end_line->Point2.Y); start_pinpad = start_extra->start.pin; end_pinpad = start_extra->end.pin; fp = 0; r_search(CURRENT->line_tree, &box, NULL, gp_line_cb, 0); r_search(CURRENT->arc_tree, &box, NULL, gp_arc_cb, 0); r_search(CURRENT->text_tree, &box, NULL, gp_text_cb, 0); r_search(CURRENT->polygon_tree, &box, NULL, gp_poly_cb, 0); r_search(PCB->Data->pin_tree, &box, NULL, gp_pin_cb, 0); r_search(PCB->Data->via_tree, &box, NULL, gp_pin_cb, 0); r_search(PCB->Data->pad_tree, &box, NULL, gp_pad_cb, 0); /* radians, absolute angle of (at the moment) the start_line */ abs_angle = fa + start_angle; #if TRACE1 pcb_printf("\033[43;30mBest: at %#mD r %#mS, angle %.1f fp %d\033[0m\n", fx, fy, fr, r2d(fa), fp); #endif #if 0 if (fa > M_PI/2 || fa < -M_PI/2) { SET_FLAG (FOUNDFLAG, line); longjmp (abort_buf, 1); } #endif if (fp) { start_extra->end.waiting_for = fp_end; return; } start_extra->end.pending = 0; /* Step 0: check for merged arcs (special case). */ if (fx == ex && fy == ey && start_arc && end_arc && start_arc->X == end_arc->X && start_arc->Y == end_arc->Y) { /* Merge arcs */ int new_delta; new_delta = end_arc->StartAngle - start_arc->StartAngle; if (start_arc->Delta > 0) { while (new_delta > 360) new_delta -= 360; while (new_delta < 0) new_delta += 360; } else { while (new_delta < -360) new_delta += 360; while (new_delta > 0) new_delta -= 360; } #if TRACE1 pcb_printf("merging arcs at %#mS nd %d\n", start_arc->X, start_arc->Y, new_delta); print_extra(sarc_extra, 0); print_extra(earc_extra, 0); #endif mark_arc_for_deletion (end_arc); mark_line_for_deletion (start_line); mark_line_for_deletion (end_line); ChangeArcAngles (CURRENT, start_arc, start_arc->StartAngle, new_delta); fix_arc_extra (start_arc, sarc_extra); did_something ++; return; } /* Step 1: adjust start_arc's angles and move start_line's Point1 to match it. */ if (start_arc) { double new_delta; int del_arc = 0; /* We must always round towards "larger arcs", whichever way that is. */ new_delta = 180 - r2d(abs_angle); #if TRACE1 printf("new_delta starts at %d vs %d < %d\n", (int)new_delta, (int)start_arc->StartAngle, (int)start_arc->Delta); #endif if (start_arc->Delta < 0) new_delta = (int)(new_delta) + 90; else new_delta = (int)new_delta - 90; new_delta = new_delta - start_arc->StartAngle; while (new_delta > start_arc->Delta+180) new_delta -= 360; while (new_delta < start_arc->Delta-180) new_delta += 360; #if TRACE1 printf("new_delta adjusts to %d\n", (int)new_delta); printf("fa = %f, new_delta ends at %.1f vs start %d\n", fa, new_delta, (int)start_arc->StartAngle); #endif if (new_delta * start_arc->Delta <= 0) del_arc = 1; ChangeArcAngles (CURRENT, start_arc, start_arc->StartAngle, new_delta); fix_arc_extra (start_arc, sarc_extra); MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point1), sarc_extra->end.x - start_line->Point1.X, sarc_extra->end.y - start_line->Point1.Y); if (del_arc) { MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point1), sarc_extra->start.x - start_line->Point1.X, sarc_extra->start.y - start_line->Point1.Y); mark_arc_for_deletion (start_arc); } } /* Step 1.5: If the "obstacle" is right at the end, ignore it. */ { double oa = start_angle+fa - M_PI/2*se_sign; double ox = fx + fr * cos(oa); double oy = fy + fr * sin(oa); #if TRACE1 pcb_printf("obstacle at %#mD angle %d = arc starts at %#mD\n", fx, fy, (int)r2d(oa), (Coord)ox, (Coord)oy); #endif if (Distance (ox, oy, end_line->Point2.X, end_line->Point2.Y) < fr * SIN1D) { /* Pretend it doesn't exist. */ fx = ex; fy = ey; } } /* Step 2: If we have no obstacles, connect start and end. */ #if TRACE1 pcb_printf("fx %#mS ex %#mS fy %#mS ey %#mS\n", fx, ex, fy, ey); #endif if (fx == ex && fy == ey) { /* No obstacles. */ #if TRACE1 printf("\033[32mno obstacles\033[0m\n"); #endif if (end_arc) { int del_arc = 0; int new_delta, end_angle, pcb_fa, end_change; end_angle = end_arc->StartAngle + end_arc->Delta; if (end_arc->Delta < 0) end_angle -= 90; else end_angle += 90; /* We must round so as to make the larger arc. */ if (end_arc->Delta < 0) pcb_fa = - r2d(start_angle + fa); else pcb_fa = 1 - r2d(start_angle + fa); end_change = pcb_fa - end_angle; while (end_change > 180) end_change -= 360; while (end_change < -180) end_change += 360; new_delta = end_arc->Delta + end_change; if (new_delta * end_arc->Delta <= 0) del_arc = 1; ChangeArcAngles (CURRENT, end_arc, end_arc->StartAngle, new_delta); fix_arc_extra (end_arc, earc_extra); MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), earc_extra->end.x - start_line->Point2.X, earc_extra->end.y - start_line->Point2.Y); if (del_arc) { MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), earc_extra->start.x - start_line->Point2.X, earc_extra->start.y - start_line->Point2.Y); mark_arc_for_deletion (end_arc); } } else { MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), end_line->Point2.X - start_line->Point2.X, end_line->Point2.Y - start_line->Point2.Y); } mark_line_for_deletion (end_line); start_extra->end.pending = 1; #if TRACE1 printf("\033[35mdid_something: no obstacles\033[0m\n"); #endif did_something ++; npulled ++; status(); return; } /* Step 3: Compute the new intersection of start_line and end_line. */ ex = start_line->Point1.X + cos(start_angle + fa) * 10000.0; ey = start_line->Point1.Y + sin(start_angle + fa) * 10000.0; #if TRACE1 pcb_printf("temp point %#mS\n", ex, ey); pcb_printf("intersect %#mS-%#mS with %#mS-%#mS\n", start_line->Point1.X, start_line->Point1.Y, ex, ey, end_line->Point1.X, end_line->Point1.Y, end_line->Point2.X, end_line->Point2.Y); #endif if (! intersection_of_lines (start_line->Point1.X, start_line->Point1.Y, ex, ey, end_line->Point1.X, end_line->Point1.Y, end_line->Point2.X, end_line->Point2.Y, &ex, &ey)) { ex = end_line->Point2.X; ey = end_line->Point2.Y; } #if TRACE1 pcb_printf("new point %#mS\n", ex, ey); #endif MoveObject (LINEPOINT_TYPE, CURRENT, end_line, &(end_line->Point1), ex - end_line->Point1.X, ey - end_line->Point1.Y); /* Step 4: Split start_line at the obstacle and insert a zero-delta arc at it. */ new_arc = create_arc (start_line, fx, fy, fr, 90-(int)(r2d(start_angle+fa)+0.5) + 90 + 90*se_sign, -se_sign); new_aextra = ARC2EXTRA (new_arc); if (start_arc) sarc_extra = ARC2EXTRA (start_arc); if (end_arc) earc_extra = ARC2EXTRA (end_arc); MoveObject (LINEPOINT_TYPE, CURRENT, start_line, &(start_line->Point2), new_aextra->start.x - start_line->Point2.X, new_aextra->start.y - start_line->Point2.Y); new_line = create_line (start_line, new_aextra->end.x, new_aextra->end.y, ex, ey); start_extra = LINE2EXTRA (start_line); new_lextra = LINE2EXTRA (new_line); end_extra = LINE2EXTRA (end_line); new_lextra->start.pin = start_extra->start.pin; new_lextra->end.pin = start_extra->end.pin; new_lextra->start.pending = 1; new_lextra->end.pending = 1; start_extra->end.next = new_aextra; new_aextra->start.next = start_extra; new_aextra->end.next = new_lextra; new_lextra->start.next = new_aextra; new_lextra->end.next = end_extra; end_extra->start.next = new_lextra; /* Step 5: Recurse. */ did_something ++; npulled ++; status(); #if TRACE0 printf("\033[35mdid_something: recursing\033[0m\n"); { int i = gui->confirm_dialog("recurse?", 0); printf("confirm = %d\n", i); if (i == 0) return; } printf("\n\033[33mRECURSING\033[0m\n\n"); IncrementUndoSerialNumber(); #endif maybe_pull_1 (new_line); } /*! * \brief Given a line with a end_next, attempt to pull both ends. */ static void maybe_pull (LineType *line, Extra *e) { #if TRACE0 printf("maybe_pull: "); print_extra (e, 0); #endif if (e->end.next && EXTRA_IS_LINE (e->end.next)) { maybe_pull_1 (line); } else { e->end.pending = 0; if (e->start.next && EXTRA_IS_LINE (e->start.next)) { reverse_line (line); maybe_pull_1 (line); } else e->start.pending = 0; } } static void validate_pair (Extra *e, End *end) { if (!end->next) return; if (end->next->start.next == e) return; if (end->next->end.next == e) return; fprintf(stderr, "no backlink!\n"); print_extra (e, 0); print_extra (end->next, 0); abort(); } static void validate_pair_cb (AnyObjectType *ptr, Extra *extra, void *userdata) { validate_pair (extra, &extra->start); validate_pair (extra, &extra->end); } static void validate_pairs () { g_hash_table_foreach (lines, (GHFunc)validate_pair_cb, NULL); #if TRACE1 printf("\narcs\n"); #endif g_hash_table_foreach (arcs, (GHFunc)validate_pair_cb, NULL); } static void FreeExtra (Extra *extra) { g_slice_free (Extra, extra); } static void mark_ends_pending (LineType *line, Extra *extra, void *userdata) { int *select_flags = userdata; if (TEST_FLAGS (*select_flags, line)) { extra->start.pending = 1; extra->end.pending = 1; } } #if TRACE1 static void trace_print_extra (AnyObjectType *ptr, Extra *extra, void *userdata) { last_pextra = (Extra *)1; print_extra(extra, 0); } static void trace_print_lines_arcs (void) { printf("\nlines\n"); g_hash_table_foreach (lines, (GHFunc)trace_print_extra, NULL); printf("\narcs\n"); g_hash_table_foreach (arcs, (GHFunc)trace_print_extra, NULL); printf("\n"); } #endif static int GlobalPuller(int argc, char **argv, Coord x, Coord y) { int select_flags = 0; setbuf(stdout, 0); nloops = 0; npulled = 0; Message ("puller! %s\n", argc > 0 ? argv[0] : ""); if (argc > 0 && strcasecmp (argv[0], "selected") == 0) select_flags = SELECTEDFLAG; if (argc > 0 && strcasecmp (argv[0], "found") == 0) select_flags = FOUNDFLAG; Message ("optimizing...\n"); /* This canonicalizes all the lines, and cleans up near-misses. */ /* hid_actionl ("djopt", "puller", 0); */ current_is_bottom = (GetLayerGroupNumberByPointer(CURRENT) == GetLayerGroupNumberBySide (BOTTOM_SIDE)); current_is_top = (GetLayerGroupNumberByPointer(CURRENT) == GetLayerGroupNumberBySide (TOP_SIDE)); lines = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)FreeExtra); arcs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)FreeExtra); Message ("pairing...\n"); find_pairs (); validate_pairs (); g_hash_table_foreach (lines, (GHFunc)mark_ends_pending, &select_flags); #if TRACE1 trace_print_lines_arcs (); #endif propogate_ends (); #if TRACE1 trace_print_lines_arcs (); trace_paths (); #endif Message ("pulling...\n"); if (setjmp(abort_buf) == 0) { #if TRACE0 int old_did_something = -1; #endif did_something = 1; while (did_something) { nloops ++; status(); did_something = 0; LINE_LOOP (CURRENT); { Extra *e = LINE2EXTRA (line); if (e->deleted) continue; #ifdef CHECK_LINE_PT_NEG if (line->Point1.X < 0) abort1(); #endif if (e->start.next || e->end.next) maybe_pull (line, e); #if TRACE0 if (did_something != old_did_something) { IncrementUndoSerialNumber(); old_did_something = did_something; if (gui->confirm_dialog("more?", 0) == 0) { did_something = 0; break; } } #endif /*gui->progress(0,0,0);*/ } END_LOOP; } } #if TRACE0 printf("\nlines\n"); g_hash_table_foreach (lines, (GHFunc)trace_print_extra, NULL); printf("\narcs\n"); g_hash_table_foreach (arcs, (GHFunc)trace_print_extra, NULL); printf("\n"); printf("\nlines\n"); #endif LINE_LOOP (CURRENT); { if (LINE2EXTRA (line)->deleted) RemoveLine (CURRENT, line); } END_LOOP; ARC_LOOP (CURRENT); { if (ARC2EXTRA (arc)->deleted) RemoveArc (CURRENT, arc); } END_LOOP; g_hash_table_unref (lines); g_hash_table_unref (arcs); IncrementUndoSerialNumber(); return 0; } /* Actions */ HID_Action puller_action_list[] = { {"Puller", "Click on a line-arc intersection or line segment", Puller, puller_help, puller_syntax}, {"GlobalPuller", 0, GlobalPuller, globalpuller_help, globalpuller_syntax} }; REGISTER_ACTIONS (puller_action_list) pcb-4.2.2/src/relocate.c0000664000076400007640000000576713533277055012000 00000000000000/*! * \file src/relocate.c * * \brief Relocate plug-in for PCB. * * \author Jean Richard * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include "config.h" #include "global.h" #include "data.h" #include "hid.h" #include "misc.h" #include "create.h" #include "rtree.h" #include "undo.h" #include "move.h" #include "draw.h" #include "set.h" /* %start-doc actions Relocate The @code{Relocate()} action in pcb that will take all selected elements and stack them up at the current crosshairs. This works well when starting a new layout and you have hundreds of parts on your workspace and you're just starting to do your component placement. Use Select Element by Name (refdes) to select the elements you want to move, and then use :Relocate() to set the position of those elements to where ever your crosshair is. TODO: Right now, if multiple elements are selected, they are all are stacked up on top of each other. Instead make them spread out the way Disperse Elements does. %end-doc */ static int relocate (int argc, char **argv, Coord x, Coord y) { Coord origin_x; Coord origin_y; Coord dx; Coord dy; /* get crosshair location and make this our "origin". */ origin_x = Crosshair.X; origin_y = Crosshair.Y; /* loop over all elements, and move selected elements to crosshair * location. */ ELEMENT_LOOP (PCB->Data); { /* only affect selected elements. */ if (TEST_FLAG (SELECTEDFLAG, element)) { /* how far does the element need to move? */ dx = origin_x - element->BoundingBox.X1; dy = origin_y - element->BoundingBox.Y1; /* snap to grid. */ dx -= (element->MarkX + dx) % PCB->Grid; dx += PCB->Grid; dy -= (element->MarkY + dy) % PCB->Grid; dy += PCB->Grid; /* move the element. */ MoveElementLowLevel (PCB->Data, element, dx, dy); /* add to the undo list. */ AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy); } } END_LOOP; /* done with our action, so increment the undo # .*/ IncrementUndoSerialNumber (); Redraw (); SetChangedFlag (true); return 0; } static HID_Action relocate_action_list[] = { { "Relocate", NULL, relocate, NULL, NULL} }; REGISTER_ACTIONS(relocate_action_list) void hid_relocate_init() { register_relocate_action_list(); } pcb-4.2.2/src/rubberband.h0000664000076400007640000000237613434555140012300 00000000000000/*! * \file src/rubberband.h * * \brief Prototypes for rubberband routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_RUBBERBAND_H #define PCB_RUBBERBAND_H #include "global.h" void LookupRubberbandLines (int, void *, void *, void *); void LookupRatLines (int, void *, void *, void *); #endif pcb-4.2.2/src/report.c0000664000076400007640000006447213533277055011513 00000000000000/*! * \file src/report.c * * \brief . * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996,1997,1998,1999 Thomas Nau * * This module, report.c, was written and is Copyright (C) 1997 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "report.h" #include "crosshair.h" #include "data.h" #include "drill.h" #include "error.h" #include "flags.h" #include "search.h" #include "misc.h" #include "mymem.h" #include "rats.h" #include "rtree.h" #include "strflags.h" #include "macro.h" #include "undo.h" #include "find.h" #include "draw.h" #include "pcb-printf.h" #ifdef HAVE_REGEX_H #include #endif #ifdef HAVE_REGCOMP #undef HAVE_RE_COMP #endif #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) #define USE_RE #endif #ifdef HAVE_LIBDMALLOC #include #endif #define USER_UNITMASK (Settings.grid_unit->allow) static int ReportDrills (int argc, char **argv, Coord x, Coord y) { DrillInfoType *AllDrills; Cardinal n; char *stringlist, *thestring; int total_drills = 0; size_t size_left; AllDrills = GetDrillInfo (PCB->Data); for (n = 0; n < AllDrills->DrillN; n++) { total_drills += AllDrills->Drill[n].PinCount; total_drills += AllDrills->Drill[n].ViaCount; } size_left = 512L + AllDrills->DrillN * 64L; stringlist = (char *)malloc (size_left); /* Use tabs for formatting since can't count on a fixed font anymore. | And even that probably isn't going to work in all cases. */ sprintf (stringlist, _("There are %d different drill sizes used in this layout, %d holes total\n\n" "Drill Diam. (%s)\t# of Pins\t# of Vias\t# of Elements\t# Unplated\n"), AllDrills->DrillN, total_drills, Settings.grid_unit->suffix); thestring = stringlist; while (size_left > 0 && *thestring != '\0') { thestring++; size_left--; } for (n = 0; n < AllDrills->DrillN; n++) { pcb_snprintf (thestring, size_left, _("%10m*\t\t%d\t\t%d\t\t%d\t\t%d\n"), Settings.grid_unit->suffix, AllDrills->Drill[n].DrillSize, AllDrills->Drill[n].PinCount, AllDrills->Drill[n].ViaCount, AllDrills->Drill[n].ElementN, AllDrills->Drill[n].UnplatedCount); while (size_left > 0 && *thestring != '\0') { thestring++; size_left--; } } FreeDrillInfo (AllDrills); /* create dialog box */ gui->report_dialog (_("Drill Report"), stringlist); free (stringlist); return 0; } static const char reportdialog_syntax[] = N_("ReportDialog()"); static const char reportdialog_help[] = N_("Report on the object under the crosshair"); static char* CreateBuriedViaDescription (int from, int to) { static char s[32]; if ((from == 0) && (to == 0)) strcpy (s, "Through-hole"); else sprintf (s, "Buried (%d:%d)", from, to); return s; } /* %start-doc actions ReportDialog This is a shortcut for @code{Report(Object)}. %end-doc */ static int ReportDialog (int argc, char **argv, Coord x, Coord y) { void *ptr1, *ptr2, *ptr3; int type; char report[2048]; type = SearchScreen (x, y, REPORT_TYPES, &ptr1, &ptr2, &ptr3); if (type == NO_TYPE) type = SearchScreen (x, y, REPORT_TYPES | LOCKED_TYPE, &ptr1, &ptr2, &ptr3); switch (type) { case VIA_TYPE: { PinType *via; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->via_tree->root, 0); return 0; } #endif via = (PinType *) ptr2; if (TEST_FLAG (HOLEFLAG, via)) pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "It is a pure hole of diameter %$mS.\n" "Name = \"%s\"." "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE), via->X, via->Y, via->DrillingHole, EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ? _("It is LOCKED.\n") : ""); else pcb_snprintf (report, sizeof (report), _("%m+VIA ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "Copper width = %$mS. Drill width = %$mS.\n" "Clearance width in polygons = %$mS.\n" "Annulus = %$mS.\n" "Solder mask hole = %$mS (gap = %$mS).\n" "Type = %s.\n" "Name = \"%s\"." "%s"), USER_UNITMASK, via->ID, flags_to_string (via->Flags, VIA_TYPE), via->X, via->Y, via->Thickness, via->DrillingHole, via->Clearance / 2, (via->Thickness - via->DrillingHole) / 2, via->Mask, (via->Mask - via->Thickness) / 2, CreateBuriedViaDescription (via->BuriedFrom, via->BuriedTo), EMPTY (via->Name), TEST_FLAG (LOCKFLAG, via) ? _("It is LOCKED.\n") : ""); break; } case PIN_TYPE: { PinType *Pin; ElementType *element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->pin_tree->root, 0); return 0; } #endif Pin = (PinType *) ptr2; element = (ElementType *) ptr1; PIN_LOOP (element); { if (pin == Pin) break; } END_LOOP; if (TEST_FLAG (HOLEFLAG, Pin)) pcb_snprintf (report, sizeof (report), _("%m+PIN ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "It is a mounting hole. Drill width = %$mS.\n" "It is owned by element %$mS.\n" "%s"), USER_UNITMASK, Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), Pin->X, Pin->Y, Pin->DrillingHole, EMPTY (element->Name[1].TextString), TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : ""); else pcb_snprintf (report, sizeof (report), _("%m+PIN ID# %ld; Flags:%s\n" "(X,Y) = %$mD.\n" "Copper width = %$mS. Drill width = %$mS.\n" "Clearance width to Polygon = %$mS.\n" "Annulus = %$mS.\n" "Solder mask hole = %$mS (gap = %$mS).\n" "Name = \"%s\".\n" "It is owned by element %s\n as pin number %s.\n" "%s"), USER_UNITMASK, Pin->ID, flags_to_string (Pin->Flags, PIN_TYPE), Pin->X, Pin->Y, Pin->Thickness, Pin->DrillingHole, Pin->Clearance / 2, (Pin->Thickness - Pin->DrillingHole) / 2, Pin->Mask, (Pin->Mask - Pin->Thickness) / 2, EMPTY (Pin->Name), EMPTY (element->Name[1].TextString), EMPTY (Pin->Number), TEST_FLAG (LOCKFLAG, Pin) ? _("It is LOCKED.\n") : ""); break; } case LINE_TYPE: { LineType *line; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->line_tree->root, 0); return 0; } #endif line = (LineType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+LINE ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = %$mD, ID = %ld.\n" "SecondPoint(X,Y) = %$mD, ID = %ld.\n" "Width = %$mS.\nClearance width in polygons = %$mS.\n" "It is on layer %d\n" "and has name \"%s\".\n" "%s"), USER_UNITMASK, line->ID, flags_to_string (line->Flags, LINE_TYPE), line->Point1.X, line->Point1.Y, line->Point1.ID, line->Point2.X, line->Point2.Y, line->Point2.ID, line->Thickness, line->Clearance / 2, GetLayerNumber (PCB->Data, (LayerType *) ptr1), UNKNOWN (line->Number), TEST_FLAG (LOCKFLAG, line) ? _("It is LOCKED.\n") : ""); break; } case RATLINE_TYPE: { RatType *line; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->rat_tree->root, 0); return 0; } #endif line = (RatType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+RAT-LINE ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = %$mD; ID = %ld; " "connects to layer group %d.\n" "SecondPoint(X,Y) = %$mD; ID = %ld; " "connects to layer group %d.\n"), USER_UNITMASK, line->ID, flags_to_string (line->Flags, LINE_TYPE), line->Point1.X, line->Point1.Y, line->Point1.ID, line->group1, line->Point2.X, line->Point2.Y, line->Point2.ID, line->group2); break; } case ARC_TYPE: { ArcType *Arc; BoxType *box; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->arc_tree->root, 0); return 0; } #endif Arc = (ArcType *) ptr2; box = GetArcEnds (Arc); pcb_snprintf (report, sizeof (report), _("%m+ARC ID# %ld; Flags:%s\n" "CenterPoint(X,Y) = %$mD.\n" "Radius = %$mS, Thickness = %$mS.\n" "Clearance width in polygons = %$mS.\n" "StartAngle = %ma degrees, DeltaAngle = %ma degrees.\n" "Bounding Box is %$mD, %$mD.\n" "That makes the end points at %$mD and %$mD.\n" "It is on layer %d.\n" "%s"), USER_UNITMASK, Arc->ID, flags_to_string (Arc->Flags, ARC_TYPE), Arc->X, Arc->Y, Arc->Width, Arc->Thickness, Arc->Clearance / 2, Arc->StartAngle, Arc->Delta, Arc->BoundingBox.X1, Arc->BoundingBox.Y1, Arc->BoundingBox.X2, Arc->BoundingBox.Y2, box->X1, box->Y1, box->X2, box->Y2, GetLayerNumber (PCB->Data, (LayerType *) ptr1), TEST_FLAG (LOCKFLAG, Arc) ? _("It is LOCKED.\n") : ""); break; } case POLYGON_TYPE: { PolygonType *Polygon; #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->polygon_tree->root, 0); return 0; } #endif Polygon = (PolygonType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+POLYGON ID# %ld; Flags:%s\n" "Its bounding box is %$mD %$mD.\n" "It has %d points and could store %d more\n" " without using more memory.\n" "It has %d holes and resides on layer %d.\n" "%s"), USER_UNITMASK, Polygon->ID, flags_to_string (Polygon->Flags, POLYGON_TYPE), Polygon->BoundingBox.X1, Polygon->BoundingBox.Y1, Polygon->BoundingBox.X2, Polygon->BoundingBox.Y2, Polygon->PointN, Polygon->PointMax - Polygon->PointN, Polygon->HoleIndexN, GetLayerNumber (PCB->Data, (LayerType *) ptr1), TEST_FLAG (LOCKFLAG, Polygon) ? _("It is LOCKED.\n") : ""); break; } case PAD_TYPE: { Coord len; PadType *Pad; ElementType *element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->pad_tree->root, 0); return 0; } #endif Pad = (PadType *) ptr2; element = (ElementType *) ptr1; PAD_LOOP (element); { { if (pad == Pad) break; } } END_LOOP; len = Distance (Pad->Point1.X, Pad->Point1.Y, Pad->Point2.X, Pad->Point2.Y); pcb_snprintf (report, sizeof (report), _("%m+PAD ID# %ld; Flags:%s\n" "FirstPoint(X,Y) = %$mD; ID = %ld.\n" "SecondPoint(X,Y) = %$mD; ID = %ld.\n" "Width = %$mS. Length = %$mS.\n" "Clearance width in polygons = %$mS.\n" "Solder mask = %$mS x %$mS (gap = %$mS).\n" "Name = \"%s\".\n" "It is owned by SMD element %s\n" " as pin number %s and is on the %s\n" "side of the board.\n" "%s"), USER_UNITMASK, Pad->ID, flags_to_string (Pad->Flags, PAD_TYPE), Pad->Point1.X, Pad->Point1.Y, Pad->Point1.ID, Pad->Point2.X, Pad->Point2.Y, Pad->Point2.ID, Pad->Thickness, len + Pad->Thickness, Pad->Clearance / 2, Pad->Mask, len + Pad->Mask, (Pad->Mask - Pad->Thickness) / 2, EMPTY (Pad->Name), EMPTY (element->Name[1].TextString), EMPTY (Pad->Number), TEST_FLAG (ONSOLDERFLAG, Pad) ? _("solder (bottom)") : _("component"), TEST_FLAG (LOCKFLAG, Pad) ? _("It is LOCKED.\n") : ""); break; } case ELEMENT_TYPE: { ElementType *element; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->element_tree->root, 0); return 0; } #endif element = (ElementType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+ELEMENT ID# %ld; Flags:%s\n" "BoundingBox %$mD %$mD.\n" "Descriptive Name \"%s\".\n" "Name on board \"%s\".\n" "Part number name \"%s\".\n" "It is %$mS tall and is located at (X,Y) = %$mD %s.\n" "Mark located at point (X,Y) = %$mD.\n" "It is on the %s side of the board.\n" "%s"), USER_UNITMASK, element->ID, flags_to_string (element->Flags, ELEMENT_TYPE), element->BoundingBox.X1, element->BoundingBox.Y1, element->BoundingBox.X2, element->BoundingBox.Y2, EMPTY (element->Name[0].TextString), EMPTY (element->Name[1].TextString), EMPTY (element->Name[2].TextString), SCALE_TEXT (FONT_CAPHEIGHT, element->Name[1].Scale), element->Name[1].X, element->Name[1].Y, TEST_FLAG (HIDENAMEFLAG, element) ? _(",\n but it's hidden") : "", element->MarkX, element->MarkY, TEST_FLAG (ONSOLDERFLAG, element) ? _("solder (bottom)") : _("component"), TEST_FLAG (LOCKFLAG, element) ? _("It is LOCKED.\n") : ""); break; } case TEXT_TYPE: #ifndef NDEBUG if (gui->shift_is_pressed ()) { LayerType *layer = (LayerType *) ptr1; __r_dump_tree (layer->text_tree->root, 0); return 0; } #endif case ELEMENTNAME_TYPE: { char laynum[32]; TextType *text; #ifndef NDEBUG if (gui->shift_is_pressed ()) { __r_dump_tree (PCB->Data->name_tree[NAME_INDEX (PCB)]->root, 0); return 0; } #endif text = (TextType *) ptr2; if (type == TEXT_TYPE) sprintf (laynum, _("It is on layer %d."), GetLayerNumber (PCB->Data, (LayerType *) ptr1)); pcb_snprintf (report, sizeof (report), _("%m+TEXT ID# %ld; Flags:%s\n" "Located at (X,Y) = %$mD.\n" "Characters are %$mS tall.\n" "Value is \"%s\".\n" "Direction is %d.\n" "The bounding box is %$mD %$mD.\n" "%s\n" "%s"), USER_UNITMASK, text->ID, flags_to_string (text->Flags, TEXT_TYPE), text->X, text->Y, SCALE_TEXT (FONT_CAPHEIGHT, text->Scale), text->TextString, text->Direction, text->BoundingBox.X1, text->BoundingBox.Y1, text->BoundingBox.X2, text->BoundingBox.Y2, (type == TEXT_TYPE) ? laynum : _("It is an element name."), TEST_FLAG (LOCKFLAG, text) ? _("It is LOCKED.\n") : ""); break; } case LINEPOINT_TYPE: case POLYGONPOINT_TYPE: { PointType *point = (PointType *) ptr2; pcb_snprintf (report, sizeof (report), _("%m+POINT ID# %ld.\n" "Located at (X,Y) = %$mD.\n" "It belongs to a %s on layer %d.\n"), USER_UNITMASK, point->ID, point->X, point->Y, (type == LINEPOINT_TYPE) ? C_("report", "line") : C_("report", "polygon"), GetLayerNumber (PCB->Data, (LayerType *) ptr1)); break; } case NO_TYPE: report[0] = '\0'; break; default: sprintf (report, _("Unknown\n")); break; } if (report[0] == '\0') { Message (_("Nothing found to report on\n")); return 1; } /* create dialog box */ gui->report_dialog (_("Report"), report); return 0; } static int ReportFoundPins (int argc, char **argv, Coord x, Coord y) { static DynamicStringType list; char temp[64]; int col = 0; DSClearString (&list); DSAddString (&list, _("The following pins/pads are FOUND:\n")); ELEMENT_LOOP (PCB->Data); { PIN_LOOP (element); { if (TEST_FLAG (FOUNDFLAG, pin)) { sprintf (temp, _("%s-%s,%c"), NAMEONPCB_NAME (element), pin->Number, ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' '); DSAddString (&list, temp); } } END_LOOP; PAD_LOOP (element); { if (TEST_FLAG (FOUNDFLAG, pad)) { sprintf (temp, _("%s-%s,%c"), NAMEONPCB_NAME (element), pad->Number, ((col++ % (COLUMNS + 1)) == COLUMNS) ? '\n' : ' '); DSAddString (&list, temp); } } END_LOOP; } END_LOOP; gui->report_dialog (_("Report"), list.Data); return 0; } /*! * \brief Assumes that we start with a blank connection state, * e.g. ClearFlagOnAllObjects() has been run. * * Does not add its own changes to the undo system */ static double XYtoNetLength (Coord x, Coord y, int *found) { double length; length = 0; *found = 0; /* NB: The third argument here, 'false' ensures LookupConnection * does not add its changes to the undo system. */ LookupConnection (x, y, false, PCB->Grid, FOUNDFLAG, true); ALLLINE_LOOP (PCB->Data); { if (TEST_FLAG (FOUNDFLAG, line)) { int dx, dy; dx = line->Point1.X - line->Point2.X; dy = line->Point1.Y - line->Point2.Y; length += hypot (dx, dy); *found = 1; } } ENDALL_LOOP; ALLARC_LOOP (PCB->Data); { if (TEST_FLAG (FOUNDFLAG, arc)) { double l; /* FIXME: we assume width==height here */ l = M_PI * 2*arc->Width * abs(arc->Delta)/360.0; length += l; *found = 1; } } ENDALL_LOOP; return length; } static int ReportAllNetLengths (int argc, char **argv, Coord x, Coord y) { int ni; int found; /* Reset all connection flags and save an undo-state to get back * to the state the board was in when we started this function. * * After this, we don't add any changes to the undo system, but * ensure we get back to a point where we can Undo() our changes * by resetting the connections with ClearFlagOnAllObjects() before * calling Undo() at the end of the procedure. */ ClearFlagOnAllObjects (FOUNDFLAG, true); IncrementUndoSerialNumber (); for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) { char *netname = PCB->NetlistLib.Menu[ni].Name + 2; char *ename = PCB->NetlistLib.Menu[ni].Entry[0].ListEntry; char *pname; bool got_one = 0; ename = strdup (ename); pname = strchr (ename, '-'); if (! pname) { free (ename); continue; } *pname++ = 0; ELEMENT_LOOP (PCB->Data); { char *es = element->Name[NAMEONPCB_INDEX].TextString; if (es && strcmp (es, ename) == 0) { PIN_LOOP (element); { if (strcmp (pin->Number, pname) == 0) { x = pin->X; y = pin->Y; got_one = 1; break; } } END_LOOP; PAD_LOOP (element); { if (strcmp (pad->Number, pname) == 0) { x = (pad->Point1.X + pad->Point2.X) / 2; y = (pad->Point1.Y + pad->Point2.Y) / 2; got_one = 1; break; } } END_LOOP; } } END_LOOP; if (got_one) { char buf[50]; const char *units_name = argv[0]; Coord length; if (argc < 1) units_name = Settings.grid_unit->suffix; length = XYtoNetLength (x, y, &found); /* Reset connectors for the next lookup */ ClearFlagOnAllObjects (FOUNDFLAG, false); pcb_snprintf(buf, sizeof (buf), _("%$m*"), units_name, length); gui->log(_("Net \"%s\" length: %s\n"), netname, buf); } } ClearFlagOnAllObjects (FOUNDFLAG, false); Undo (true); return 0; } static int ReportNetLength (int argc, char **argv, Coord x, Coord y) { Coord length = 0; char *netname = 0; int found = 0; gui->get_coords (_("Click on a connection"), &x, &y); /* Reset all connection flags and save an undo-state to get back * to the state the board was in when we started this function. * * After this, we don't add any changes to the undo system, but * ensure we get back to a point where we can Undo() our changes * by resetting the connections with ClearFlagOnAllObjects() before * calling Undo() at the end of the procedure. */ ClearFlagOnAllObjects (FOUNDFLAG, true); IncrementUndoSerialNumber (); length = XYtoNetLength (x, y, &found); if (!found) { ClearFlagOnAllObjects (FOUNDFLAG, false); Undo (true); gui->log (_("No net under cursor.\n")); return 1; } ELEMENT_LOOP (PCB->Data); { PIN_LOOP (element); { if (TEST_FLAG (FOUNDFLAG, pin)) { int ni, nei; char *ename = element->Name[NAMEONPCB_INDEX].TextString; char *pname = pin->Number; char *n; if (ename && pname) { n = Concat (ename, _("-"), pname, NULL); for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++) { if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0) { netname = PCB->NetlistLib.Menu[ni].Name + 2; goto got_net_name; /* four for loops deep */ } } } } } END_LOOP; PAD_LOOP (element); { if (TEST_FLAG (FOUNDFLAG, pad)) { int ni, nei; char *ename = element->Name[NAMEONPCB_INDEX].TextString; char *pname = pad->Number; char *n; if (ename && pname) { n = Concat (ename, _("-"), pname, NULL); for (ni = 0; ni < PCB->NetlistLib.MenuN; ni++) for (nei = 0; nei < PCB->NetlistLib.Menu[ni].EntryN; nei++) { if (strcmp (PCB->NetlistLib.Menu[ni].Entry[nei].ListEntry, n) == 0) { netname = PCB->NetlistLib.Menu[ni].Name + 2; goto got_net_name; /* four for loops deep */ } } } } } END_LOOP; } END_LOOP; got_net_name: ClearFlagOnAllObjects (FOUNDFLAG, false); Undo (true); { char buf[50]; pcb_snprintf(buf, sizeof (buf), _("%$m*"), Settings.grid_unit->suffix, length); if (netname) gui->log (_("Net \"%s\" length: %s\n"), netname, buf); else gui->log (_("Net length: %s\n"), buf); } return 0; } static int ReportNetLengthByName (char *tofind, int x, int y) { int result; char *netname = 0; Coord length = 0; int found = 0; int i; LibraryMenuType *net; ConnectionType conn; int net_found = 0; #if defined(USE_RE) int use_re = 0; #endif #if defined(HAVE_REGCOMP) regex_t elt_pattern; regmatch_t match; #endif #if defined(HAVE_RE_COMP) char *elt_pattern; #endif if (!PCB) return 1; if (!tofind) return 1; #if defined(USE_RE) use_re = 1; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { net = PCB->NetlistLib.Menu + i; if (strcasecmp (tofind, net->Name + 2) == 0) use_re = 0; } if (use_re) { #if defined(HAVE_REGCOMP) result = regcomp (&elt_pattern, tofind, REG_EXTENDED | REG_ICASE | REG_NOSUB); if (result) { char errorstring[128]; regerror (result, &elt_pattern, errorstring, 128); Message (_("regexp error: %s\n"), errorstring); regfree (&elt_pattern); return (1); } #endif #if defined(HAVE_RE_COMP) if ((elt_pattern = re_comp (tofind)) != NULL) { Message (_("re_comp error: %s\n"), elt_pattern); return (1); } #endif } #endif for (i = 0; i < PCB->NetlistLib.MenuN; i++) { net = PCB->NetlistLib.Menu + i; #if defined(USE_RE) if (use_re) { #if defined(HAVE_REGCOMP) if (regexec (&elt_pattern, net->Name + 2, 1, &match, 0) != 0) continue; #endif #if defined(HAVE_RE_COMP) if (re_exec (net->Name + 2) != 1) continue; #endif } else #endif if (strcasecmp (net->Name + 2, tofind)) continue; if (SeekPad (net->Entry, &conn, false)) { switch (conn.type) { case PIN_TYPE: x = ((PinType *) (conn.ptr2))->X; y = ((PinType *) (conn.ptr2))->Y; net_found=1; break; case PAD_TYPE: x = ((PadType *) (conn.ptr2))->Point1.X; y = ((PadType *) (conn.ptr2))->Point1.Y; net_found=1; break; } if (net_found) break; } } if (!net_found) { gui->log (_("No net named \"%s\"\n"), tofind); return 1; } #ifdef HAVE_REGCOMP if (use_re) regfree (&elt_pattern); #endif /* Reset all connection flags and save an undo-state to get back * to the state the board was in when we started. * * After this, we don't add any changes to the undo system, but * ensure we get back to a point where we can Undo() our changes * by resetting the connections with ClearFlagOnAllObjects() before * calling Undo() when we are finished. */ ClearFlagOnAllObjects (FOUNDFLAG, true); IncrementUndoSerialNumber (); length = XYtoNetLength (x, y, &found); netname = net->Name + 2; ClearFlagOnAllObjects (FOUNDFLAG, false); Undo (true); if (!found) { if (net_found) gui->log (_("Net found, but no lines or arcs were flagged.\n")); else gui->log (_("Net not found.\n")); return 1; } { char buf[50]; pcb_snprintf(buf, 50, _("%$m*"), Settings.grid_unit->suffix, length); if (netname) gui->log (_("Net \"%s\" length: %s\n"), netname, buf); else gui->log (_("Net length: %s\n"), buf); } return 0; } static const char report_syntax[] = N_("Report(Object|DrillReport|FoundPins|NetLength|AllNetLengths|[,name])"); static const char report_help[] = N_("Produce various report."); /* %start-doc actions Report @table @code @item Object The object under the crosshair will be reported, describing various aspects of the object. @item DrillReport A report summarizing the number of drill sizes used, and how many of each, will be produced. @item FoundPins A report listing all pins and pads which are marked as ``found'' will be produced. @item NetLength The name and length of the net under the crosshair will be reported to the message log. @item AllNetLengths The name and length of the net under the crosshair will be reported to the message log. An optional parameter specifies mm, mil, pcb, or in units @end table %end-doc */ /*! * \brief Reports on an object. */ static int Report (int argc, char **argv, Coord x, Coord y) { if ((argc < 1) || (argc > 2)) AUSAGE (report); else if (strcasecmp (argv[0], "Object") == 0) { gui->get_coords (_("Click on an object"), &x, &y); return ReportDialog (argc - 1, argv + 1, x, y); } else if (strcasecmp (argv[0], "DrillReport") == 0) return ReportDrills (argc - 1, argv + 1, x, y); else if (strcasecmp (argv[0], "FoundPins") == 0) return ReportFoundPins (argc - 1, argv + 1, x, y); else if ((strcasecmp (argv[0], "NetLength") == 0) && (argc == 1)) return ReportNetLength (argc - 1, argv + 1, x, y); else if (strcasecmp (argv[0], "AllNetLengths") == 0) return ReportAllNetLengths (argc - 1, argv + 1, x, y); else if ((strcasecmp (argv[0], "NetLength") == 0) && (argc == 2)) return ReportNetLengthByName (argv[1], x, y); else if (argc == 2) AUSAGE (report); else AFAIL (report); return 1; } HID_Action report_action_list[] = { {"ReportObject", N_("Click on an object"), ReportDialog, reportdialog_help, reportdialog_syntax} , {"Report", 0, Report, report_help, report_syntax} }; REGISTER_ACTIONS (report_action_list) pcb-4.2.2/src/search.h0000664000076400007640000000601413434555140011430 00000000000000/*! * \file src/search.h * * \brief Prototypes for search routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_SEARCH_H #define PCB_SEARCH_H #include "global.h" #define SLOP 5 /* --------------------------------------------------------------------------- * some useful macros */ /* --------------------------------------------------------------------------- * some define to check for 'type' in box */ #define POINT_IN_BOX(x,y,b) \ ((x) >= (b)->X1 && (x) <= (b)->X2 && (y) >= (b)->Y1 && (y) <= (b)->Y2) #define VIA_OR_PIN_IN_BOX(v,b) \ POINT_IN_BOX((v)->X,(v)->Y,(b)) #define LINE_IN_BOX(l,b) \ (POINT_IN_BOX((l)->Point1.X,(l)->Point1.Y,(b)) && \ POINT_IN_BOX((l)->Point2.X,(l)->Point2.Y,(b))) #define PAD_IN_BOX(p,b) LINE_IN_BOX((LineType *)(p),(b)) #define BOX_IN_BOX(b1,b) \ ((b1)->X1 >= (b)->X1 && (b1)->X2 <= (b)->X2 && \ ((b1)->Y1 >= (b)->Y1 && (b1)->Y2 <= (b)->Y2)) #define TEXT_IN_BOX(t,b) \ (BOX_IN_BOX(&((t)->BoundingBox), (b))) #define POLYGON_IN_BOX(p,b) \ (BOX_IN_BOX(&((p)->BoundingBox), (b))) #define ELEMENT_IN_BOX(e,b) \ (BOX_IN_BOX(&((e)->BoundingBox), (b))) #define ARC_IN_BOX(a,b) \ (BOX_IN_BOX(&((a)->BoundingBox), (b))) /* --------------------------------------------------------------------------- * prototypes */ bool IsPointOnLine (Coord, Coord, Coord, LineType *); bool IsPointOnPin (Coord, Coord, Coord, PinType *); bool IsPointOnArc (Coord, Coord, Coord, ArcType *); bool IsPointOnLineEnd (Coord, Coord, RatType *); bool IsLineInRectangle (Coord, Coord, Coord, Coord, LineType *); bool IsLineInQuadrangle (PointType p[4], LineType * Line); bool IsArcInRectangle (Coord, Coord, Coord, Coord, ArcType *); bool IsPointInPad (Coord, Coord, Coord, PadType *); bool IsPointInBox (Coord, Coord, BoxType *, Coord); int SearchObjectByLocation (unsigned, void **, void **, void **, Coord, Coord, Coord); int SearchScreen (Coord, Coord, int, void **, void **, void **); int SearchObjectByID (DataType *, void **, void **, void **, int, int); ElementType * SearchElementByName (DataType *, char *); int SearchLayerByName (DataType *Base, char *Name); #endif pcb-4.2.2/src/autoroute.h0000664000076400007640000000246513434555140012220 00000000000000/*! * \file src/autoroute.h * * \brief Prototypes for autoroute routines. * * \author This file, autoroute.h, was written and is * Copyright (c) 2001 C. Scott Ananian. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu * */ #ifndef PCB_AUTOROUTE_H #define PCB_AUTOROUTE_H #include "global.h" bool AutoRoute (bool); #endif pcb-4.2.2/src/insert.c0000664000076400007640000002121713434555140011464 00000000000000/*! * \file src/insert.c * * \brief Functions used to insert points into objects. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include "copy.h" #include "create.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "insert.h" #include "line.h" #include "misc.h" #include "move.h" #include "polygon.h" #include "rtree.h" #include "search.h" #include "select.h" #include "set.h" #include "undo.h" #ifdef HAVE_LIBDMALLOC #include #endif /* --------------------------------------------------------------------------- * some local prototypes */ static void *InsertPointIntoLine (LayerType *, LineType *); static void *InsertPointIntoPolygon (LayerType *, PolygonType *); static void *InsertPointIntoRat (RatType *); /* --------------------------------------------------------------------------- * some local identifiers */ static Coord InsertX, InsertY; /* used by local routines as offset */ static Cardinal InsertAt; static bool InsertLast; static bool Forcible; static ObjectFunctionType InsertFunctions = { InsertPointIntoLine, NULL, InsertPointIntoPolygon, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, InsertPointIntoRat }; /*! * \brief Inserts a point into a rat-line. */ static void * InsertPointIntoRat (RatType *Rat) { LineType *newone; newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point1.X, Rat->Point1.Y, InsertX, InsertY, Settings.LineThickness, 2 * Settings.Keepaway, Rat->Flags); if (!newone) return newone; AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone); EraseRat (Rat); DrawLine (CURRENT, newone); newone = CreateDrawnLineOnLayer (CURRENT, Rat->Point2.X, Rat->Point2.Y, InsertX, InsertY, Settings.LineThickness, 2 * Settings.Keepaway, Rat->Flags); if (newone) { AddObjectToCreateUndoList (LINE_TYPE, CURRENT, newone, newone); DrawLine (CURRENT, newone); } MoveObjectToRemoveUndoList (RATLINE_TYPE, Rat, Rat, Rat); Draw (); return (newone); } /*! * \brief Inserts a point into a line. */ static void * InsertPointIntoLine (LayerType *Layer, LineType *Line) { LineType *line; Coord X, Y; if (((Line->Point1.X == InsertX) && (Line->Point1.Y == InsertY)) || ((Line->Point2.X == InsertX) && (Line->Point2.Y == InsertY))) return (NULL); X = Line->Point2.X; Y = Line->Point2.Y; AddObjectToMoveUndoList (LINEPOINT_TYPE, Layer, Line, &Line->Point2, InsertX - X, InsertY - Y); EraseLine (Line); r_delete_entry (Layer->line_tree, (BoxType *) Line); RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line); Line->Point2.X = InsertX; Line->Point2.Y = InsertY; SetLineBoundingBox (Line); r_insert_entry (Layer->line_tree, (BoxType *) Line, 0); ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line); DrawLine (Layer, Line); /* we must create after playing with Line since creation may * invalidate the line pointer */ if ((line = CreateDrawnLineOnLayer (Layer, InsertX, InsertY, X, Y, Line->Thickness, Line->Clearance, Line->Flags))) { AddObjectToCreateUndoList (LINE_TYPE, Layer, line, line); DrawLine (Layer, line); ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, line); /* creation call adds it to the rtree */ } Draw (); return (line); } /*! * \brief Inserts a point into a polygon. */ static void * InsertPointIntoPolygon (LayerType *Layer, PolygonType *Polygon) { PointType save; Cardinal n; LineType line; if (!Forcible) { /* * first make sure adding the point is sensible */ line.Thickness = 0; line.Point1 = Polygon->Points[prev_contour_point (Polygon, InsertAt)]; line.Point2 = Polygon->Points[InsertAt]; if (IsPointOnLine ((float) InsertX, (float) InsertY, 0.0, &line)) return (NULL); } /* * second, shift the points up to make room for the new point */ ErasePolygon (Polygon); r_delete_entry (Layer->polygon_tree, (BoxType *) Polygon); save = *CreateNewPointInPolygon (Polygon, InsertX, InsertY); for (n = Polygon->PointN - 1; n > InsertAt; n--) Polygon->Points[n] = Polygon->Points[n - 1]; /* Shift up indices of any holes */ for (n = 0; n < Polygon->HoleIndexN; n++) if (Polygon->HoleIndex[n] > InsertAt || (InsertLast && Polygon->HoleIndex[n] == InsertAt)) Polygon->HoleIndex[n]++; Polygon->Points[InsertAt] = save; SetChangedFlag (true); AddObjectToInsertPointUndoList (POLYGONPOINT_TYPE, Layer, Polygon, &Polygon->Points[InsertAt]); SetPolygonBoundingBox (Polygon); r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0); InitClip (PCB->Data, Layer, Polygon); if (Forcible || !RemoveExcessPolygonPoints (Layer, Polygon)) { DrawPolygon (Layer, Polygon); Draw (); } return (&Polygon->Points[InsertAt]); } /*! * \brief Inserts point into objects. */ void * InsertPointIntoObject (int Type, void *Ptr1, void *Ptr2, Cardinal * Ptr3, Coord DX, Coord DY, bool Force, bool insert_last) { void *ptr; /* setup offset */ InsertX = DX; InsertY = DY; InsertAt = *Ptr3; InsertLast = insert_last; Forcible = Force; /* the operation insert the points to the undo-list */ ptr = ObjectOperation (&InsertFunctions, Type, Ptr1, Ptr2, Ptr3); if (ptr != NULL) IncrementUndoSerialNumber (); return (ptr); } /*! * \brief Adjusts the insert point to make 45 degree lines as necessary. */ PointType * AdjustInsertPoint (void) { static PointType InsertedPoint; double m; Coord x, y, m1, m2; LineType *line = (LineType *) Crosshair.AttachedObject.Ptr2; if (Crosshair.AttachedObject.State == STATE_FIRST) return NULL; Crosshair.AttachedObject.Ptr3 = &InsertedPoint; if (gui->shift_is_pressed ()) { AttachedLineType myline; /* only force 45 degree for nearest point */ if (Distance (Crosshair.X, Crosshair.Y, line->Point1.X, line->Point1.Y) < Distance (Crosshair.X, Crosshair.Y, line->Point2.X, line->Point2.Y)) myline.Point1 = myline.Point2 = line->Point1; else myline.Point1 = myline.Point2 = line->Point2; FortyFiveLine (&myline); InsertedPoint.X = myline.Point2.X; InsertedPoint.Y = myline.Point2.Y; return &InsertedPoint; } if (PCB->RatDraw || TEST_FLAG (ALLDIRECTIONFLAG, PCB)) { InsertedPoint.X = Crosshair.X; InsertedPoint.Y = Crosshair.Y; return &InsertedPoint; } if (Crosshair.X == line->Point1.X) m1 = 2; /* 2 signals infinite slope */ else { m = (double) (Crosshair.Y - line->Point1.Y) / (Crosshair.X - line->Point1.X); m1 = 0; if (m > TAN_30_DEGREE) m1 = (m > TAN_60_DEGREE) ? 2 : 1; else if (m < -TAN_30_DEGREE) m1 = (m < -TAN_60_DEGREE) ? 2 : -1; } if (Crosshair.X == line->Point2.X) m2 = 2; /* 2 signals infinite slope */ else { m = (double) (Crosshair.Y - line->Point2.Y) / (Crosshair.X - line->Point2.X); m2 = 0; if (m > TAN_30_DEGREE) m2 = (m > TAN_60_DEGREE) ? 2 : 1; else if (m < -TAN_30_DEGREE) m2 = (m < -TAN_60_DEGREE) ? 2 : -1; } if (m1 == m2) { InsertedPoint.X = line->Point1.X; InsertedPoint.Y = line->Point1.Y; return &InsertedPoint; } if (m1 == 2) { x = line->Point1.X; y = line->Point2.Y + m2 * (line->Point1.X - line->Point2.X); } else if (m2 == 2) { x = line->Point2.X; y = line->Point1.Y + m1 * (line->Point2.X - line->Point1.X); } else { x = (line->Point2.Y - line->Point1.Y + m1 * line->Point1.X - m2 * line->Point2.X) / (m1 - m2); y = (m1 * line->Point2.Y - m1 * m2 * line->Point2.X - m2 * line->Point1.Y + m1 * m2 * line->Point1.X) / (m1 - m2); } InsertedPoint.X = x; InsertedPoint.Y = y; return &InsertedPoint; } pcb-4.2.2/src/polygon.h0000664000076400007640000000747213533277055011671 00000000000000/*! * \file src/polygon.h * * \brief Prototypes for polygon editing routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_POLYGON_H #define PCB_POLYGON_H #include "global.h" /* Implementation constants */ #define POLY_CIRC_SEGS 40 #define POLY_CIRC_SEGS_F ((float)POLY_CIRC_SEGS) /*! * \brief Adjustment to make the segments outline the circle rather than * connect points on the circle: * \f$ 1 - cos ( \frac {\alpha} {2} ) < \frac { ( \frac {\alpha} {2} ) ^ 2 } {2} \f$ */ #define POLY_CIRC_RADIUS_ADJ (1.0 + M_PI / POLY_CIRC_SEGS_F * \ M_PI / POLY_CIRC_SEGS_F / 2.0) /*! * \brief Polygon diverges from modelled arc no more than * MAX_ARC_DEVIATION * thick. */ #define POLY_ARC_MAX_DEVIATION 0.02 /* Prototypes */ void polygon_init (void); Cardinal polygon_point_idx (PolygonType * polygon, PointType * point); Cardinal polygon_point_contour (PolygonType * polygon, Cardinal point); Cardinal prev_contour_point (PolygonType * polygon, Cardinal point); Cardinal next_contour_point (PolygonType * polygon, Cardinal point); Cardinal GetLowestDistancePolygonPoint (PolygonType *, Coord, Coord); bool RemoveExcessPolygonPoints (LayerType *, PolygonType *); void GoToPreviousPoint (void); void ClosePolygon (void); void CopyAttachedPolygonToLayer (void); int PolygonHoles (PolygonType *ptr, const BoxType *range, int (*callback) (PLINE *, void *user_data), void *user_data); int PlowsPolygon (DataType *, int, void *, void *, int (*callback) (DataType *, LayerType *, PolygonType *, int, void *, void *, void *), void *userdata); void ComputeNoHoles (PolygonType *poly); POLYAREA * original_poly(PolygonType *); POLYAREA * ContourToPoly (PLINE *); POLYAREA * PolygonToPoly (PolygonType *); POLYAREA * RectPoly (Coord x1, Coord x2, Coord y1, Coord y2); POLYAREA * CirclePoly (Coord x, Coord y, Coord radius); POLYAREA * OctagonPoly(Coord x, Coord y, Coord radius); POLYAREA * LinePoly(LineType *l, Coord thick); POLYAREA * ArcPoly(ArcType *l, Coord thick); POLYAREA * PinPoly(PinType *l, Coord thick, Coord clear); POLYAREA * BoxPolyBloated (BoxType *box, Coord radius); void frac_circle (PLINE *, Coord, Coord, Vector, int); int InitClip(DataType *d, LayerType *l, PolygonType *p); void RestoreToPolygon(DataType *, int, void *, void *); void ClearFromPolygon(DataType *, int, void *, void *); bool IsPointInPolygon (Coord, Coord, Coord, PolygonType *); bool IsPointInPolygonIgnoreHoles (Coord, Coord, PolygonType *); bool IsRectangleInPolygon (Coord, Coord, Coord, Coord, PolygonType *); bool isects (POLYAREA *, PolygonType *, bool); bool MorphPolygon (LayerType *, PolygonType *); void NoHolesPolygonDicer (PolygonType *p, const BoxType *clip, void (*emit) (PLINE *, void *), void *user_data); void PolyToPolygonsOnLayer (DataType *, LayerType *, POLYAREA *, FlagType); #endif pcb-4.2.2/src/change.c0000664000076400007640000016727113533277055011426 00000000000000/*! * \file src/change.c * * \brief Functions used to change object properties. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996, 2005 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "global.h" #include "change.h" #include "create.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "error.h" #include "mymem.h" #include "misc.h" #include "mirror.h" #include "polygon.h" #include "rats.h" #include "remove.h" #include "rtree.h" #include "search.h" #include "select.h" #include "set.h" #include "thermal.h" #include "undo.h" #ifdef HAVE_LIBDMALLOC #include #endif /* --------------------------------------------------------------------------- * some local prototypes */ static void *ChangePinSize (ElementType *, PinType *); static void *ChangePinClearSize (ElementType *, PinType *); static void *ChangePinMaskSize (ElementType *, PinType *); static void *ChangePadSize (ElementType *, PadType *); static void *ChangePadClearSize (ElementType *, PadType *); static void *ChangePadMaskSize (ElementType *, PadType *); static void *ChangePin2ndSize (ElementType *, PinType *); static void *ChangeElement2ndSize (ElementType *); static void *ChangeViaSize (PinType *); static void *ChangeVia2ndSize (PinType *); static void *ChangeViaClearSize (PinType *); static void *ChangeViaMaskSize (PinType *); static void *ChangeLineSize (LayerType *, LineType *); static void *ChangeLineClearSize (LayerType *, LineType *); static void *ChangePolygonClearSize (LayerType *, PolygonType *); static void *ChangeArcSize (LayerType *, ArcType *); static void *ChangeArcClearSize (LayerType *, ArcType *); static void *ChangeTextSize (LayerType *, TextType *); static void *ChangeElementSize (ElementType *); static void *ChangeElementNameSize (ElementType *); static void *ChangePinName (ElementType *, PinType *); static void *ChangePadName (ElementType *, PadType *); static void *ChangeViaName (PinType *); static void *ChangeLineName (LayerType *, LineType *); static void *ChangeElementName (ElementType *); static void *ChangeTextName (LayerType *, TextType *); static void *ChangeElementSquare (ElementType *); static void *SetElementSquare (ElementType *); static void *ClrElementSquare (ElementType *); static void *ChangeElementOctagon (ElementType *); static void *SetElementOctagon (ElementType *); static void *ClrElementOctagon (ElementType *); static void *ChangePinSquare (ElementType *, PinType *); static void *SetPinSquare (ElementType *, PinType *); static void *ClrPinSquare (ElementType *, PinType *); static void *ChangePinOctagon (ElementType *, PinType *); static void *SetPinOctagon (ElementType *, PinType *); static void *ClrPinOctagon (ElementType *, PinType *); static void *ChangeViaOctagon (PinType *); static void *SetViaOctagon (PinType *); static void *ClrViaOctagon (PinType *); static void *ChangePadSquare (ElementType *, PadType *); static void *SetPadSquare (ElementType *, PadType *); static void *ClrPadSquare (ElementType *, PadType *); static void *ChangeViaThermal (PinType *); static void *ChangePinThermal (ElementType *, PinType *); static void *ChangeLineJoin (LayerType *, LineType *); static void *SetLineJoin (LayerType *, LineType *); static void *ClrLineJoin (LayerType *, LineType *); static void *ChangeArcJoin (LayerType *, ArcType *); static void *SetArcJoin (LayerType *, ArcType *); static void *ClrArcJoin (LayerType *, ArcType *); static void *ChangeTextJoin (LayerType *, TextType *); static void *SetTextJoin (LayerType *, TextType *); static void *ClrTextJoin (LayerType *, TextType *); static void *ChangePolyClear (LayerType *, PolygonType *); /* --------------------------------------------------------------------------- * some local identifiers */ /*! Either the new value or the change in value */ static int Value; /*! Used as boolean to indicate that Value is an absolute or delta */ static int Absolute; static char *NewName; /* new name */ static ObjectFunctionType ChangeSizeFunctions = { ChangeLineSize, ChangeTextSize, ChangePolyClear, ChangeViaSize, ChangeElementSize, /* changes silk screen line width */ ChangeElementNameSize, ChangePinSize, ChangePadSize, NULL, NULL, ChangeArcSize, NULL }; static ObjectFunctionType Change2ndSizeFunctions = { NULL, NULL, NULL, ChangeVia2ndSize, ChangeElement2ndSize, NULL, ChangePin2ndSize, NULL, NULL, NULL, NULL, NULL }; static ObjectFunctionType ChangeThermalFunctions = { NULL, NULL, NULL, ChangeViaThermal, NULL, NULL, ChangePinThermal, NULL, NULL, NULL, NULL, NULL }; static ObjectFunctionType ChangeClearSizeFunctions = { ChangeLineClearSize, NULL, ChangePolygonClearSize, /* just to tell the user not to :-) */ ChangeViaClearSize, NULL, NULL, ChangePinClearSize, ChangePadClearSize, NULL, NULL, ChangeArcClearSize, NULL }; static ObjectFunctionType ChangeNameFunctions = { ChangeLineName, ChangeTextName, NULL, ChangeViaName, ChangeElementName, NULL, ChangePinName, ChangePadName, NULL, NULL, NULL, NULL }; static ObjectFunctionType ChangeSquareFunctions = { NULL, NULL, NULL, NULL, ChangeElementSquare, NULL, ChangePinSquare, ChangePadSquare, NULL, NULL, NULL, NULL }; static ObjectFunctionType ChangeJoinFunctions = { ChangeLineJoin, ChangeTextJoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ChangeArcJoin, NULL }; static ObjectFunctionType ChangeOctagonFunctions = { NULL, NULL, NULL, ChangeViaOctagon, ChangeElementOctagon, NULL, ChangePinOctagon, NULL, NULL, NULL, NULL, NULL }; static ObjectFunctionType ChangeMaskSizeFunctions = { NULL, NULL, NULL, ChangeViaMaskSize, #if 0 ChangeElementMaskSize, #else NULL, #endif NULL, ChangePinMaskSize, ChangePadMaskSize, NULL, NULL, NULL, NULL }; static ObjectFunctionType SetSquareFunctions = { NULL, NULL, NULL, NULL, SetElementSquare, NULL, SetPinSquare, SetPadSquare, NULL, NULL, NULL, NULL }; static ObjectFunctionType SetJoinFunctions = { SetLineJoin, SetTextJoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, SetArcJoin, NULL }; static ObjectFunctionType SetOctagonFunctions = { NULL, NULL, NULL, SetViaOctagon, SetElementOctagon, NULL, SetPinOctagon, NULL, NULL, NULL, NULL, NULL }; static ObjectFunctionType ClrSquareFunctions = { NULL, NULL, NULL, NULL, ClrElementSquare, NULL, ClrPinSquare, ClrPadSquare, NULL, NULL, NULL, NULL }; static ObjectFunctionType ClrJoinFunctions = { ClrLineJoin, ClrTextJoin, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ClrArcJoin, NULL }; static ObjectFunctionType ClrOctagonFunctions = { NULL, NULL, NULL, ClrViaOctagon, ClrElementOctagon, NULL, ClrPinOctagon, NULL, NULL, NULL, NULL, NULL }; /*! * \brief Changes the thermal on a via. * * \return TRUE if changed. */ static void * ChangeViaThermal (PinType *Via) { AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, false); RestoreToPolygon (PCB->Data, VIA_TYPE, CURRENT, Via); AddObjectToFlagUndoList (VIA_TYPE, Via, Via, Via); if (!Value) /* remove the thermals */ CLEAR_THERM (INDEXOFCURRENT, Via); else ASSIGN_THERM (INDEXOFCURRENT, Value, Via); AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, true); ClearFromPolygon (PCB->Data, VIA_TYPE, CURRENT, Via); DrawVia (Via); return Via; } /*! * \brief Changes the thermal on a pin. * * \return TRUE if changed. */ static void * ChangePinThermal (ElementType *element, PinType *Pin) { AddObjectToClearPolyUndoList (PIN_TYPE, element, Pin, Pin, false); RestoreToPolygon (PCB->Data, VIA_TYPE, CURRENT, Pin); AddObjectToFlagUndoList (PIN_TYPE, element, Pin, Pin); if (!Value) /* remove the thermals */ CLEAR_THERM (INDEXOFCURRENT, Pin); else ASSIGN_THERM (INDEXOFCURRENT, Value, Pin); AddObjectToClearPolyUndoList (PIN_TYPE, element, Pin, Pin, true); ClearFromPolygon (PCB->Data, VIA_TYPE, CURRENT, Pin); DrawPin (Pin); return Pin; } /*! * \brief Changes the size of a via. * * \return TRUE if changed. */ static void * ChangeViaSize (PinType *Via) { Coord new_value = Absolute ? Value : Via->Thickness + Value; if (TEST_FLAG (LOCKFLAG, Via)) return (NULL); if (!TEST_FLAG (HOLEFLAG, Via) && new_value <= MAX_PINORVIASIZE && new_value >= MIN_PINORVIASIZE && new_value > Via->DrillingHole && new_value != Via->Thickness) { AddObjectToSizeUndoList (VIA_TYPE, Via, Via, Via); EraseVia (Via); r_delete_entry (PCB->Data->via_tree, (BoxType *) Via); RestoreToPolygon (PCB->Data, PIN_TYPE, Via, Via); if (Via->Mask) { AddObjectToMaskSizeUndoList (VIA_TYPE, Via, Via, Via); Via->Mask += new_value - Via->Thickness; } Via->Thickness = new_value; SetPinBoundingBox (Via); r_insert_entry (PCB->Data->via_tree, (BoxType *) Via, 0); ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via); DrawVia (Via); return (Via); } return (NULL); } /*! * \brief Changes the drilling hole of a via. * * \return TRUE if changed. */ static void * ChangeVia2ndSize (PinType *Via) { Coord new_value = (Absolute) ? Value : Via->DrillingHole + Value; if (TEST_FLAG (LOCKFLAG, Via)) return (NULL); if (new_value <= MAX_PINORVIASIZE && new_value >= MIN_PINORVIAHOLE && (TEST_FLAG (HOLEFLAG, Via) || new_value < Via->Thickness) && new_value != Via->DrillingHole) { AddObjectTo2ndSizeUndoList (VIA_TYPE, Via, Via, Via); EraseVia (Via); RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via); Via->DrillingHole = new_value; if (TEST_FLAG (HOLEFLAG, Via)) { AddObjectToSizeUndoList (VIA_TYPE, Via, Via, Via); Via->Thickness = new_value; } ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via); DrawVia (Via); return (Via); } return (NULL); } /*! * \brief Changes the clearance size of a via. * * \return TRUE if changed. */ static void * ChangeViaClearSize (PinType *Via) { Coord new_value = (Absolute) ? Value : Via->Clearance + Value; if (TEST_FLAG (LOCKFLAG, Via)) return (NULL); new_value = MIN (MAX_LINESIZE, new_value); if (new_value < 0) new_value = 0; if (Value < 0 && new_value < PCB->Bloat * 2) new_value = 0; if ((Value > 0 || Absolute) && new_value < PCB->Bloat * 2) new_value = PCB->Bloat * 2 + 2; if (Via->Clearance == new_value) return NULL; RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via); AddObjectToClearSizeUndoList (VIA_TYPE, Via, Via, Via); EraseVia (Via); r_delete_entry (PCB->Data->via_tree, (BoxType *) Via); Via->Clearance = new_value; SetPinBoundingBox (Via); r_insert_entry (PCB->Data->via_tree, (BoxType *) Via, 0); ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via); DrawVia (Via); Via->Element = NULL; return (Via); } /*! * \brief Changes the size of a pin. * * \return TRUE if changed. */ static void * ChangePinSize (ElementType *Element, PinType *Pin) { Coord new_value = (Absolute) ? Value : Pin->Thickness + Value; if (TEST_FLAG (LOCKFLAG, Pin)) return (NULL); if (!TEST_FLAG (HOLEFLAG, Pin) && new_value <= MAX_PINORVIASIZE && new_value >= MIN_PINORVIASIZE && new_value > Pin->DrillingHole && new_value != Pin->Thickness) { AddObjectToSizeUndoList (PIN_TYPE, Element, Pin, Pin); AddObjectToMaskSizeUndoList (PIN_TYPE, Element, Pin, Pin); ErasePin (Pin); r_delete_entry (PCB->Data->pin_tree, &Pin->BoundingBox); RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin); Pin->Mask += new_value - Pin->Thickness; Pin->Thickness = new_value; /* SetElementBB updates all associated rtrees */ SetElementBoundingBox (PCB->Data, Element, &PCB->Font); ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin); DrawPin (Pin); return (Pin); } return (NULL); } /*! * \brief Changes the clearance size of a pin. * * \return TRUE if changed. */ static void * ChangePinClearSize (ElementType *Element, PinType *Pin) { Coord new_value = (Absolute) ? Value : Pin->Clearance + Value; if (TEST_FLAG (LOCKFLAG, Pin)) return (NULL); new_value = MIN (MAX_LINESIZE, new_value); if (new_value < 0) new_value = 0; if (Value < 0 && new_value < PCB->Bloat * 2) new_value = 0; if ((Value > 0 || Absolute) && new_value < PCB->Bloat * 2) new_value = PCB->Bloat * 2 + 2; if (Pin->Clearance == new_value) return NULL; RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin); AddObjectToClearSizeUndoList (PIN_TYPE, Element, Pin, Pin); ErasePin (Pin); r_delete_entry (PCB->Data->pin_tree, &Pin->BoundingBox); Pin->Clearance = new_value; /* SetElementBB updates all associated rtrees */ SetElementBoundingBox (PCB->Data, Element, &PCB->Font); ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin); DrawPin (Pin); return (Pin); } /*! * \brief Changes the size of a pad. * * \return TRUE if changed. */ static void * ChangePadSize (ElementType *Element, PadType *Pad) { Coord new_value = (Absolute) ? Value : Pad->Thickness + Value; if (TEST_FLAG (LOCKFLAG, Pad)) return (NULL); if (new_value <= MAX_PADSIZE && new_value >= MIN_PADSIZE && new_value != Pad->Thickness) { AddObjectToSizeUndoList (PAD_TYPE, Element, Pad, Pad); AddObjectToMaskSizeUndoList (PAD_TYPE, Element, Pad, Pad); RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad); ErasePad (Pad); r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox); Pad->Mask += new_value - Pad->Thickness; Pad->Thickness = new_value; /* SetElementBB updates all associated rtrees */ SetElementBoundingBox (PCB->Data, Element, &PCB->Font); ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad); DrawPad (Pad); return (Pad); } return (NULL); } /*! * \brief Changes the clearance size of a pad. * * \return TRUE if changed. */ static void * ChangePadClearSize (ElementType *Element, PadType *Pad) { Coord new_value = (Absolute) ? Value : Pad->Clearance + Value; if (TEST_FLAG (LOCKFLAG, Pad)) return (NULL); new_value = MIN (MAX_LINESIZE, new_value); if (new_value < 0) new_value = 0; if (Value < 0 && new_value < PCB->Bloat * 2) new_value = 0; if ((Value > 0 || Absolute) && new_value < PCB->Bloat * 2) new_value = PCB->Bloat * 2 + 2; if (new_value == Pad->Clearance) return NULL; AddObjectToClearSizeUndoList (PAD_TYPE, Element, Pad, Pad); RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad); ErasePad (Pad); r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox); Pad->Clearance = new_value; /* SetElementBB updates all associated rtrees */ SetElementBoundingBox (PCB->Data, Element, &PCB->Font); ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad); DrawPad (Pad); return Pad; } /*! * \brief Changes the drilling hole of all pins of an element. * * \return TRUE if changed. */ static void * ChangeElement2ndSize (ElementType *Element) { bool changed = false; Coord new_value; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); PIN_LOOP (Element); { new_value = (Absolute) ? Value : pin->DrillingHole + Value; if (new_value <= MAX_PINORVIASIZE && new_value >= MIN_PINORVIAHOLE && (TEST_FLAG (HOLEFLAG, pin) || new_value <= pin->Thickness) && new_value != pin->DrillingHole) { changed = true; AddObjectTo2ndSizeUndoList (PIN_TYPE, Element, pin, pin); ErasePin (pin); RestoreToPolygon (PCB->Data, PIN_TYPE, Element, pin); pin->DrillingHole = new_value; if (TEST_FLAG (HOLEFLAG, pin)) { AddObjectToSizeUndoList (PIN_TYPE, Element, pin, pin); pin->Thickness = new_value; } ClearFromPolygon (PCB->Data, PIN_TYPE, Element, pin); DrawPin (pin); } } END_LOOP; if (changed) return (Element); else return (NULL); } /*! * \brief Changes the drilling hole of a pin. * * \return TRUE if changed. */ static void * ChangePin2ndSize (ElementType *Element, PinType *Pin) { Coord new_value = (Absolute) ? Value : Pin->DrillingHole + Value; if (TEST_FLAG (LOCKFLAG, Pin)) return (NULL); if (new_value <= MAX_PINORVIASIZE && new_value >= MIN_PINORVIAHOLE && (TEST_FLAG (HOLEFLAG, Pin) || new_value < Pin->Thickness) && new_value != Pin->DrillingHole) { AddObjectTo2ndSizeUndoList (PIN_TYPE, Element, Pin, Pin); ErasePin (Pin); RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin); Pin->DrillingHole = new_value; if (TEST_FLAG (HOLEFLAG, Pin)) { AddObjectToSizeUndoList (PIN_TYPE, Element, Pin, Pin); Pin->Thickness = new_value; } ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin); DrawPin (Pin); return (Pin); } return (NULL); } /*! * \brief Changes the size of a line. * * \return TRUE if changed. */ static void * ChangeLineSize (LayerType *Layer, LineType *Line) { Coord new_value = (Absolute) ? Value : Line->Thickness + Value; if (TEST_FLAG (LOCKFLAG, Line)) return (NULL); if (new_value <= MAX_LINESIZE && new_value >= MIN_LINESIZE && new_value != Line->Thickness) { AddObjectToSizeUndoList (LINE_TYPE, Layer, Line, Line); EraseLine (Line); r_delete_entry (Layer->line_tree, (BoxType *) Line); RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line); Line->Thickness = new_value; SetLineBoundingBox (Line); r_insert_entry (Layer->line_tree, (BoxType *) Line, 0); ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line); DrawLine (Layer, Line); return (Line); } return (NULL); } /*! * \brief Changes the clearance size of a line. * * \return TRUE if changed. */ static void * ChangeLineClearSize (LayerType *Layer, LineType *Line) { Coord new_value = (Absolute) ? Value : Line->Clearance + Value; if (TEST_FLAG (LOCKFLAG, Line) || !TEST_FLAG (CLEARLINEFLAG, Line)) return (NULL); new_value = MIN (MAX_LINESIZE, MAX (new_value, PCB->Bloat * 2 + 2)); if (new_value != Line->Clearance) { AddObjectToClearSizeUndoList (LINE_TYPE, Layer, Line, Line); RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line); EraseLine (Line); r_delete_entry (Layer->line_tree, (BoxType *) Line); Line->Clearance = new_value; if (Line->Clearance == 0) { CLEAR_FLAG (CLEARLINEFLAG, Line); Line->Clearance = MIL_TO_COORD(10); } SetLineBoundingBox (Line); r_insert_entry (Layer->line_tree, (BoxType *) Line, 0); ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line); DrawLine (Layer, Line); return (Line); } return (NULL); } /*! * \brief Handle attempts to change the clearance of a polygon. */ static void * ChangePolygonClearSize (LayerType *Layer, PolygonType *poly) { static int shown_this_message = 0; if (!shown_this_message) { gui->confirm_dialog (_("To change the clearance of objects in a polygon, " "change the objects, not the polygon.\n" "Hint: To set a minimum clearance for a group of objects, " "select them all then :MinClearGap(Selected,=10,mil)"), "Ok", NULL); shown_this_message = 1; } return (NULL); } /*! * \brief Changes the size of an arc. * * \return TRUE if changed. */ static void * ChangeArcSize (LayerType *Layer, ArcType *Arc) { Coord new_value = (Absolute) ? Value : Arc->Thickness + Value; if (TEST_FLAG (LOCKFLAG, Arc)) return (NULL); if (new_value <= MAX_LINESIZE && new_value >= MIN_LINESIZE && new_value != Arc->Thickness) { AddObjectToSizeUndoList (ARC_TYPE, Layer, Arc, Arc); EraseArc (Arc); r_delete_entry (Layer->arc_tree, (BoxType *) Arc); RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc); Arc->Thickness = new_value; SetArcBoundingBox (Arc); r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0); ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc); DrawArc (Layer, Arc); return (Arc); } return (NULL); } /*! * \brief Changes the clearance size of an arc. * * \return TRUE if changed. */ static void * ChangeArcClearSize (LayerType *Layer, ArcType *Arc) { Coord new_value = (Absolute) ? Value : Arc->Clearance + Value; if (TEST_FLAG (LOCKFLAG, Arc) || !TEST_FLAG (CLEARLINEFLAG, Arc)) return (NULL); new_value = MIN (MAX_LINESIZE, MAX (new_value, PCB->Bloat * 2 + 2)); if (new_value != Arc->Clearance) { AddObjectToClearSizeUndoList (ARC_TYPE, Layer, Arc, Arc); EraseArc (Arc); r_delete_entry (Layer->arc_tree, (BoxType *) Arc); RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc); Arc->Clearance = new_value; if (Arc->Clearance == 0) { CLEAR_FLAG (CLEARLINEFLAG, Arc); Arc->Clearance = MIL_TO_COORD(10); } SetArcBoundingBox (Arc); r_insert_entry (Layer->arc_tree, (BoxType *) Arc, 0); ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc); DrawArc (Layer, Arc); return (Arc); } return (NULL); } /*! * \brief Changes the scaling factor of a text object. * * \return TRUE if changed. */ static void * ChangeTextSize (LayerType *Layer, TextType *Text) { int new_value = (Absolute != 0 ? 0 : Text->Scale) + (double)(Absolute != 0 ? Value : Value) / (double)FONT_CAPHEIGHT * 100.; if (TEST_FLAG (LOCKFLAG, Text)) return (NULL); if (new_value <= MAX_TEXTSCALE && new_value >= MIN_TEXTSCALE && new_value != Text->Scale) { AddObjectToSizeUndoList (TEXT_TYPE, Layer, Text, Text); EraseText (Layer, Text); r_delete_entry (Layer->text_tree, (BoxType *) Text); RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text); Text->Scale = new_value; SetTextBoundingBox (&PCB->Font, Text); r_insert_entry (Layer->text_tree, (BoxType *) Text, 0); ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text); DrawText (Layer, Text); return (Text); } return (NULL); } /*! * \brief Changes the scaling factor of an element's outline. * * \return TRUE if changed. */ static void * ChangeElementSize (ElementType *Element) { Coord new_value; bool changed = false; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); if (PCB->ElementOn) EraseElement (Element); ELEMENTLINE_LOOP (Element); { new_value = (Absolute) ? Value : line->Thickness + Value; if (new_value <= MAX_LINESIZE && new_value >= MIN_LINESIZE && new_value != line->Thickness) { AddObjectToSizeUndoList (ELEMENTLINE_TYPE, Element, line, line); line->Thickness = new_value; changed = true; } } END_LOOP; ARC_LOOP (Element); { new_value = (Absolute) ? Value : arc->Thickness + Value; if (new_value <= MAX_LINESIZE && new_value >= MIN_LINESIZE && new_value != arc->Thickness) { AddObjectToSizeUndoList (ELEMENTARC_TYPE, Element, arc, arc); arc->Thickness = new_value; changed = true; } } END_LOOP; if (PCB->ElementOn) { DrawElement (Element); } if (changed) return (Element); return (NULL); } /*! * \brief Changes the scaling factor of a elementname object. * * \return TRUE if changed. */ static void * ChangeElementNameSize (ElementType *Element) { int new_value = (Absolute != 0 ? 0 : DESCRIPTION_TEXT (Element).Scale) + (double)(Absolute != 0 ? Value : Value) / (double)FONT_CAPHEIGHT * 100.; if (TEST_FLAG (LOCKFLAG, &Element->Name[0])) return (NULL); if (new_value <= MAX_TEXTSCALE && new_value >= MIN_TEXTSCALE) { EraseElementName (Element); ELEMENTTEXT_LOOP (Element); { AddObjectToSizeUndoList (ELEMENTNAME_TYPE, Element, text, text); r_delete_entry (PCB->Data->name_tree[n], (BoxType *) text); text->Scale = new_value; SetTextBoundingBox (&PCB->Font, text); r_insert_entry (PCB->Data->name_tree[n], (BoxType *) text, 0); } END_LOOP; DrawElementName (Element); return (Element); } return (NULL); } /*! * \brief Changes the name of a via. */ static void * ChangeViaName (PinType *Via) { char *old = Via->Name; if (TEST_FLAG (DISPLAYNAMEFLAG, Via)) { ErasePinName (Via); Via->Name = NewName; DrawPinName (Via); } else Via->Name = NewName; return (old); } /*! * \brief Changes the name of a pin. */ static void * ChangePinName (ElementType *Element, PinType *Pin) { char *old = Pin->Name; (void) Element; /* get rid of 'unused...' warnings */ if (TEST_FLAG (DISPLAYNAMEFLAG, Pin)) { ErasePinName (Pin); Pin->Name = NewName; DrawPinName (Pin); } else Pin->Name = NewName; return (old); } /*! * \brief Changes the name of a pad. */ static void * ChangePadName (ElementType *Element, PadType *Pad) { char *old = Pad->Name; (void) Element; /* get rid of 'unused...' warnings */ if (TEST_FLAG (DISPLAYNAMEFLAG, Pad)) { ErasePadName (Pad); Pad->Name = NewName; DrawPadName (Pad); } else Pad->Name = NewName; return (old); } /*! * \brief Changes the name of a line. */ static void * ChangeLineName (LayerType *Layer, LineType *Line) { char *old = Line->Number; (void) Layer; Line->Number = NewName; return (old); } /*! * \brief Changes the layout-name of an element. * * Change the specified text on an element, either on the board (give * PCB, PCB->Data) or in a buffer (give NULL, Buffer->Data). * * \return The old string is returned, and must be properly freed by the * caller. */ char * ChangeElementText (PCBType *pcb, DataType *data, ElementType *Element, int which, char *new_name) { char *old = Element->Name[which].TextString; #ifdef DEBUG printf("In ChangeElementText, updating old TextString %s to %s\n", old, new_name); #endif if (pcb && which == NAME_INDEX (pcb)) EraseElementName (Element); r_delete_entry (data->name_tree[which], & Element->Name[which].BoundingBox); Element->Name[which].TextString = new_name; SetTextBoundingBox (&PCB->Font, &Element->Name[which]); r_insert_entry (data->name_tree[which], & Element->Name[which].BoundingBox, 0); if (pcb && which == NAME_INDEX (pcb)) DrawElementName (Element); return old; } static void * ChangeElementName (ElementType *Element) { if (TEST_FLAG (LOCKFLAG, &Element->Name[0])) return (NULL); if (NAME_INDEX (PCB) == NAMEONPCB_INDEX) { if (TEST_FLAG (UNIQUENAMEFLAG, PCB) && UniqueElementName (PCB->Data, NewName) != NewName) { Message (_("Error: The name \"%s\" is not unique!\n"), NewName); return ((char *) -1); } } return ChangeElementText (PCB, PCB->Data, Element, NAME_INDEX (PCB), NewName); } /*! * \brief Sets data of a text object and calculates bounding box. * * Memory must have already been allocated. * The one for the new string is allocated. * * \return True if the string has been changed. */ static void * ChangeTextName (LayerType *Layer, TextType *Text) { char *old = Text->TextString; if (TEST_FLAG (LOCKFLAG, Text)) return (NULL); EraseText (Layer, Text); r_delete_entry (Layer->text_tree, (BoxType *) Text); RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text); Text->TextString = NewName; /* calculate size of the bounding box */ SetTextBoundingBox (&PCB->Font, Text); r_insert_entry(Layer->text_tree, (BoxType *) Text, 0); ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text); DrawText (Layer, Text); return (old); } /*! * \brief Changes the name of a layout; memory has to be already * allocated. */ bool ChangeLayoutName (char *Name) { free (PCB->Name); PCB->Name = Name; hid_action ("PCBChanged"); return (true); } /*! * \brief Changes the side of the board an element is on. * * \return TRUE if done. */ bool ChangeElementSide (ElementType *Element, Coord yoff) { if (TEST_FLAG (LOCKFLAG, Element)) return (false); EraseElement (Element); AddObjectToMirrorUndoList (ELEMENT_TYPE, Element, Element, Element, yoff); MirrorElementCoordinates (PCB->Data, Element, yoff); DrawElement (Element); return (true); } /*! * \brief Changes the name of a layer; memory has to be already * allocated. */ bool ChangeLayerName (LayerType *Layer, char *Name) { free (CURRENT->Name); CURRENT->Name = Name; hid_action ("LayersChanged"); return (true); } /*! * \brief Changes the clearance flag of a line. */ static void * ChangeLineJoin (LayerType *Layer, LineType *Line) { if (TEST_FLAG (LOCKFLAG, Line)) return (NULL); EraseLine (Line); if (TEST_FLAG(CLEARLINEFLAG, Line)) { AddObjectToClearPolyUndoList (LINE_TYPE, Layer, Line, Line, false); RestoreToPolygon (PCB->Data, LINE_TYPE, Layer, Line); } AddObjectToFlagUndoList (LINE_TYPE, Layer, Line, Line); TOGGLE_FLAG (CLEARLINEFLAG, Line); if (TEST_FLAG(CLEARLINEFLAG, Line)) { AddObjectToClearPolyUndoList (LINE_TYPE, Layer, Line, Line, true); ClearFromPolygon (PCB->Data, LINE_TYPE, Layer, Line); } DrawLine (Layer, Line); return (Line); } /*! * \brief Sets the clearance flag of a line. */ static void * SetLineJoin (LayerType *Layer, LineType *Line) { if (TEST_FLAG (LOCKFLAG, Line) || TEST_FLAG (CLEARLINEFLAG, Line)) return (NULL); return ChangeLineJoin (Layer, Line); } /*! * \brief Clears the clearance flag of a line. */ static void * ClrLineJoin (LayerType *Layer, LineType *Line) { if (TEST_FLAG (LOCKFLAG, Line) || !TEST_FLAG (CLEARLINEFLAG, Line)) return (NULL); return ChangeLineJoin (Layer, Line); } /*! * \brief Changes the clearance flag of an arc. */ static void * ChangeArcJoin (LayerType *Layer, ArcType *Arc) { if (TEST_FLAG (LOCKFLAG, Arc)) return (NULL); EraseArc (Arc); if (TEST_FLAG (CLEARLINEFLAG, Arc)) { RestoreToPolygon (PCB->Data, ARC_TYPE, Layer, Arc); AddObjectToClearPolyUndoList (ARC_TYPE, Layer, Arc, Arc, false); } AddObjectToFlagUndoList (ARC_TYPE, Layer, Arc, Arc); TOGGLE_FLAG (CLEARLINEFLAG, Arc); if (TEST_FLAG (CLEARLINEFLAG, Arc)) { ClearFromPolygon (PCB->Data, ARC_TYPE, Layer, Arc); AddObjectToClearPolyUndoList (ARC_TYPE, Layer, Arc, Arc, true); } DrawArc (Layer, Arc); return (Arc); } /*! * \brief Sets the clearance flag of an arc. */ static void * SetArcJoin (LayerType *Layer, ArcType *Arc) { if (TEST_FLAG (LOCKFLAG, Arc) || TEST_FLAG (CLEARLINEFLAG, Arc)) return (NULL); return ChangeArcJoin (Layer, Arc); } /*! * \brief Clears the clearance flag of an arc. */ static void * ClrArcJoin (LayerType *Layer, ArcType *Arc) { if (TEST_FLAG (LOCKFLAG, Arc) || !TEST_FLAG (CLEARLINEFLAG, Arc)) return (NULL); return ChangeArcJoin (Layer, Arc); } /*! * \brief Changes the clearance flag of a text. */ static void * ChangeTextJoin (LayerType *Layer, TextType *Text) { if (TEST_FLAG (LOCKFLAG, Text)) return (NULL); EraseText (Layer, Text); if (TEST_FLAG(CLEARLINEFLAG, Text)) { AddObjectToClearPolyUndoList (TEXT_TYPE, Layer, Text, Text, false); RestoreToPolygon (PCB->Data, TEXT_TYPE, Layer, Text); } AddObjectToFlagUndoList (TEXT_TYPE, Layer, Text, Text); TOGGLE_FLAG (CLEARLINEFLAG, Text); if (TEST_FLAG(CLEARLINEFLAG, Text)) { AddObjectToClearPolyUndoList (TEXT_TYPE, Layer, Text, Text, true); ClearFromPolygon (PCB->Data, TEXT_TYPE, Layer, Text); } DrawText (Layer, Text); return (Text); } /*! * \brief Sets the clearance flag of a text. */ static void * SetTextJoin (LayerType *Layer, TextType *Text) { if (TEST_FLAG (LOCKFLAG, Text) || TEST_FLAG (CLEARLINEFLAG, Text)) return (NULL); return ChangeTextJoin (Layer, Text); } /*! * \brief Clears the clearance flag of a text. */ static void * ClrTextJoin (LayerType *Layer, TextType *Text) { if (TEST_FLAG (LOCKFLAG, Text) || !TEST_FLAG (CLEARLINEFLAG, Text)) return (NULL); return ChangeTextJoin (Layer, Text); } /*! * \brief Changes the square flag of all pins on an element. */ static void * ChangeElementSquare (ElementType *Element) { void *ans = NULL; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); PIN_LOOP (Element); { ans = ChangePinSquare (Element, pin); } END_LOOP; PAD_LOOP (Element); { ans = ChangePadSquare (Element, pad); } END_LOOP; return (ans); } /*! * \brief Sets the square flag of all pins on an element. */ static void * SetElementSquare (ElementType *Element) { void *ans = NULL; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); PIN_LOOP (Element); { ans = SetPinSquare (Element, pin); } END_LOOP; PAD_LOOP (Element); { ans = SetPadSquare (Element, pad); } END_LOOP; return (ans); } /*! * \brief Clears the square flag of all pins on an element. */ static void * ClrElementSquare (ElementType *Element) { void *ans = NULL; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); PIN_LOOP (Element); { ans = ClrPinSquare (Element, pin); } END_LOOP; PAD_LOOP (Element); { ans = ClrPadSquare (Element, pad); } END_LOOP; return (ans); } /*! * \brief Changes the octagon flags of all pins of an element. */ static void * ChangeElementOctagon (ElementType *Element) { void *result = NULL; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); PIN_LOOP (Element); { ChangePinOctagon (Element, pin); result = Element; } END_LOOP; return (result); } /*! * \brief Sets the octagon flags of all pins of an element. */ static void * SetElementOctagon (ElementType *Element) { void *result = NULL; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); PIN_LOOP (Element); { SetPinOctagon (Element, pin); result = Element; } END_LOOP; return (result); } /*! * \brief Clears the octagon flags of all pins of an element. */ static void * ClrElementOctagon (ElementType *Element) { void *result = NULL; if (TEST_FLAG (LOCKFLAG, Element)) return (NULL); PIN_LOOP (Element); { ClrPinOctagon (Element, pin); result = Element; } END_LOOP; return (result); } /*! * \brief Changes the square flag of a pad. */ static void * ChangePadSquare (ElementType *Element, PadType *Pad) { if (TEST_FLAG (LOCKFLAG, Pad)) return (NULL); ErasePad (Pad); AddObjectToClearPolyUndoList (PAD_TYPE, Element, Pad, Pad, false); RestoreToPolygon (PCB->Data, PAD_TYPE, Element, Pad); AddObjectToFlagUndoList (PAD_TYPE, Element, Pad, Pad); TOGGLE_FLAG (SQUAREFLAG, Pad); AddObjectToClearPolyUndoList (PAD_TYPE, Element, Pad, Pad, true); ClearFromPolygon (PCB->Data, PAD_TYPE, Element, Pad); DrawPad (Pad); return (Pad); } /*! * \brief Sets the square flag of a pad. */ static void * SetPadSquare (ElementType *Element, PadType *Pad) { if (TEST_FLAG (LOCKFLAG, Pad) || TEST_FLAG (SQUAREFLAG, Pad)) return (NULL); return (ChangePadSquare (Element, Pad)); } /*! * \brief Clears the square flag of a pad. */ static void * ClrPadSquare (ElementType *Element, PadType *Pad) { if (TEST_FLAG (LOCKFLAG, Pad) || !TEST_FLAG (SQUAREFLAG, Pad)) return (NULL); return (ChangePadSquare (Element, Pad)); } /*! * \brief Changes the square flag of a pin. */ static void * ChangePinSquare (ElementType *Element, PinType *Pin) { if (TEST_FLAG (LOCKFLAG, Pin)) return (NULL); ErasePin (Pin); AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, false); RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin); AddObjectToFlagUndoList (PIN_TYPE, Element, Pin, Pin); TOGGLE_FLAG (SQUAREFLAG, Pin); AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, true); ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin); DrawPin (Pin); return (Pin); } /*! * \brief Sets the square flag of a pin. */ static void * SetPinSquare (ElementType *Element, PinType *Pin) { if (TEST_FLAG (LOCKFLAG, Pin) || TEST_FLAG (SQUAREFLAG, Pin)) return (NULL); return (ChangePinSquare (Element, Pin)); } /*! * \brief Clears the square flag of a pin. */ static void * ClrPinSquare (ElementType *Element, PinType *Pin) { if (TEST_FLAG (LOCKFLAG, Pin) || !TEST_FLAG (SQUAREFLAG, Pin)) return (NULL); return (ChangePinSquare (Element, Pin)); } /*! * \brief Changes the octagon flag of a via. */ static void * ChangeViaOctagon (PinType *Via) { if (TEST_FLAG (LOCKFLAG, Via)) return (NULL); EraseVia (Via); AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, false); RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via); AddObjectToFlagUndoList (VIA_TYPE, Via, Via, Via); TOGGLE_FLAG (OCTAGONFLAG, Via); AddObjectToClearPolyUndoList (VIA_TYPE, Via, Via, Via, true); ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via); DrawVia (Via); return (Via); } /*! * \brief Sets the octagon flag of a via. */ static void * SetViaOctagon (PinType *Via) { if (TEST_FLAG (LOCKFLAG, Via) || TEST_FLAG (OCTAGONFLAG, Via)) return (NULL); return (ChangeViaOctagon (Via)); } /*! * \brief Clears the octagon flag of a via. */ static void * ClrViaOctagon (PinType *Via) { if (TEST_FLAG (LOCKFLAG, Via) || !TEST_FLAG (OCTAGONFLAG, Via)) return (NULL); return (ChangeViaOctagon (Via)); } /*! * \brief Changes the octagon flag of a pin. */ static void * ChangePinOctagon (ElementType *Element, PinType *Pin) { if (TEST_FLAG (LOCKFLAG, Pin)) return (NULL); ErasePin (Pin); AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, false); RestoreToPolygon (PCB->Data, PIN_TYPE, Element, Pin); AddObjectToFlagUndoList (PIN_TYPE, Element, Pin, Pin); TOGGLE_FLAG (OCTAGONFLAG, Pin); AddObjectToClearPolyUndoList (PIN_TYPE, Element, Pin, Pin, true); ClearFromPolygon (PCB->Data, PIN_TYPE, Element, Pin); DrawPin (Pin); return (Pin); } /*! * \brief Sets the octagon flag of a pin. */ static void * SetPinOctagon (ElementType *Element, PinType *Pin) { if (TEST_FLAG (LOCKFLAG, Pin) || TEST_FLAG (OCTAGONFLAG, Pin)) return (NULL); return (ChangePinOctagon (Element, Pin)); } /*! * \brief Clears the octagon flag of a pin. */ static void * ClrPinOctagon (ElementType *Element, PinType *Pin) { if (TEST_FLAG (LOCKFLAG, Pin) || !TEST_FLAG (OCTAGONFLAG, Pin)) return (NULL); return (ChangePinOctagon (Element, Pin)); } /*! * \brief Changes the hole flag of a via. */ bool ChangeHole (PinType *Via) { if (TEST_FLAG (LOCKFLAG, Via)) return (false); EraseVia (Via); AddObjectToFlagUndoList (VIA_TYPE, Via, Via, Via); AddObjectToMaskSizeUndoList (VIA_TYPE, Via, Via, Via); r_delete_entry (PCB->Data->via_tree, (BoxType *) Via); RestoreToPolygon (PCB->Data, VIA_TYPE, Via, Via); TOGGLE_FLAG (HOLEFLAG, Via); if (TEST_FLAG (HOLEFLAG, Via)) { /* A tented via becomes an minimally untented hole. An untented via retains its mask clearance. */ if (Via->Mask > Via->Thickness) { Via->Mask = (Via->DrillingHole + (Via->Mask - Via->Thickness)); } else if (Via->Mask < Via->DrillingHole) { Via->Mask = Via->DrillingHole + 2 * MASKFRAME; } } else { Via->Mask = (Via->Thickness + (Via->Mask - Via->DrillingHole)); } SetPinBoundingBox (Via); r_insert_entry (PCB->Data->via_tree, (BoxType *) Via, 0); ClearFromPolygon (PCB->Data, VIA_TYPE, Via, Via); DrawVia (Via); Draw (); return (true); } /*! * \brief Changes the nopaste flag of a pad. */ bool ChangePaste (PadType *Pad) { if (TEST_FLAG (LOCKFLAG, Pad)) return (false); ErasePad (Pad); AddObjectToFlagUndoList (PAD_TYPE, Pad, Pad, Pad); TOGGLE_FLAG (NOPASTEFLAG, Pad); DrawPad (Pad); Draw (); return (true); } /*! * \brief Changes the CLEARPOLY flag of a polygon. */ static void * ChangePolyClear (LayerType *Layer, PolygonType *Polygon) { if (TEST_FLAG (LOCKFLAG, Polygon)) return (NULL); AddObjectToClearPolyUndoList (POLYGON_TYPE, Layer, Polygon, Polygon, true); AddObjectToFlagUndoList (POLYGON_TYPE, Layer, Polygon, Polygon); TOGGLE_FLAG (CLEARPOLYFLAG, Polygon); InitClip (PCB->Data, Layer, Polygon); DrawPolygon (Layer, Polygon); return (Polygon); } /*! * \brief Changes the side of all selected and visible elements. * * \return True if anything has changed. */ bool ChangeSelectedElementSide (void) { bool change = false; /* setup identifiers */ if (PCB->PinOn && PCB->ElementOn) ELEMENT_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, element)) { change |= ChangeElementSide (element, 0); } } END_LOOP; if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the thermals on all selected and visible pins and/or * vias. * * \return True if anything has changed. */ bool ChangeSelectedThermals (int types, int therm_style) { bool change = false; Value = therm_style; change = SelectedOperation (&ChangeThermalFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the thermals on all selected and visible pins and/or * vias. * * \return True if anything has changed. */ bool ChangeSelectedViaLayers (int from, int to) { bool change = false; int new_from; int new_to; int i; VIA_LOOP (PCB->Data); { if (TEST_FLAG (LOCKFLAG, via)) continue; if (TEST_FLAG (SELECTEDFLAG, via)) { new_from = (from != -1)?from:via->BuriedFrom; new_to = (to != -1)?to:via->BuriedTo; if (new_from == new_to) continue; /* special case - changing TH via "from" layer sets "to" layer to bottom layer */ if (!VIA_IS_BURIED (via) && (to == -1)) new_to = GetMaxBottomLayer (); for (i=0; i < max_copper_layer; i++) { /* AddObjectToClearPolyUndoList (VIA_TYPE, &(PCB->Data->Layer[i]), via, via, false); not needed? */ RestoreToPolygon (PCB->Data, VIA_TYPE, &(PCB->Data->Layer[i]), via); } AddObjectToSetViaLayersUndoList (via, via, via); via->BuriedFrom = new_from; via->BuriedTo = new_to; if (VIA_IS_BURIED (via)) { SanitizeBuriedVia (via); for (i=0; i < max_copper_layer; i++) { /* AddObjectToClearPolyUndoList (VIA_TYPE, &(PCB->Data->Layer[i]), via, via, true); not needed? */ ClearFromPolygon (PCB->Data, VIA_TYPE, &(PCB->Data->Layer[i]), via); } DrawVia (via); } change = true; } } END_LOOP; if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the size of all selected and visible object types. * * \return True if anything has changed. */ bool ChangeSelectedSize (int types, Coord Difference, bool fixIt) { bool change = false; /* setup identifiers */ Absolute = (fixIt) ? 1 : 0; Value = Difference; change = SelectedOperation (&ChangeSizeFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the clearance size of all selected and visible objects. * * \return True if anything has changed. */ bool ChangeSelectedClearSize (int types, Coord Difference, bool fixIt) { bool change = false; /* setup identifiers */ Absolute = (fixIt) ? 1 : 0; Value = Difference; if (TEST_FLAG (SHOWMASKFLAG, PCB)) change = SelectedOperation (&ChangeMaskSizeFunctions, false, types); else change = SelectedOperation (&ChangeClearSizeFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the 2nd size (drilling hole) of all selected and * visible objects. * * \return True if anything has changed. */ bool ChangeSelected2ndSize (int types, Coord Difference, bool fixIt) { bool change = false; /* setup identifiers */ Absolute = (fixIt) ? 1 : 0; Value = Difference; change = SelectedOperation (&Change2ndSizeFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the clearance flag (join) of all selected and visible * lines and/or arcs. * * \return True if anything has changed. */ bool ChangeSelectedJoin (int types) { bool change = false; change = SelectedOperation (&ChangeJoinFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the clearance flag (join) of all selected and visible * lines and/or arcs. * * \return True if anything has changed. */ bool SetSelectedJoin (int types) { bool change = false; change = SelectedOperation (&SetJoinFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the clearance flag (join) of all selected and visible * lines and/or arcs. * * \return True if anything has changed. */ bool ClrSelectedJoin (int types) { bool change = false; change = SelectedOperation (&ClrJoinFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the square-flag of all selected and visible pins or * pads. * * \return True if anything has changed. */ bool ChangeSelectedSquare (int types) { bool change = false; change = SelectedOperation (&ChangeSquareFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Sets the square-flag of all selected and visible pins or pads. * * \return True if anything has changed. */ bool SetSelectedSquare (int types) { bool change = false; change = SelectedOperation (&SetSquareFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Clears the square-flag of all selected and visible pins or * pads. * * \return True if anything has changed. */ bool ClrSelectedSquare (int types) { bool change = false; change = SelectedOperation (&ClrSquareFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the octagon-flag of all selected and visible pins and * vias. * * \return True if anything has changed. */ bool ChangeSelectedOctagon (int types) { bool change = false; change = SelectedOperation (&ChangeOctagonFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Sets the octagon-flag of all selected and visible pins and * vias. * * \return True if anything has changed. */ bool SetSelectedOctagon (int types) { bool change = false; change = SelectedOperation (&SetOctagonFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Clears the octagon-flag of all selected and visible pins and * vias. * * \return True if anything has changed. */ bool ClrSelectedOctagon (int types) { bool change = false; change = SelectedOperation (&ClrOctagonFunctions, false, types); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the hole-flag of all selected and visible vias. * * \return True if anything has changed. */ bool ChangeSelectedHole (void) { bool change = false; if (PCB->ViaOn) VIA_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, via)) change |= ChangeHole (via); } END_LOOP; if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the no paste-flag of all selected and visible pads. * * \return True if anything has changed. */ bool ChangeSelectedPaste (void) { bool change = false; ALLPAD_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, pad)) change |= ChangePaste (pad); } ENDALL_LOOP; if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the size of the passed object. * * \return True if anything is changed. */ bool ChangeObjectSize (int Type, void *Ptr1, void *Ptr2, void *Ptr3, Coord Difference, bool fixIt) { bool change; /* setup identifier */ Absolute = (fixIt) ? 1 : 0; Value = Difference; change = (ObjectOperation (&ChangeSizeFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the clearance size of the passed object. * * \return True if anything is changed. */ bool ChangeObjectClearSize (int Type, void *Ptr1, void *Ptr2, void *Ptr3, Coord Difference, bool fixIt) { bool change; /* setup identifier */ Absolute = (fixIt) ? 1 : 0; Value = Difference; if (TEST_FLAG (SHOWMASKFLAG, PCB)) change = (ObjectOperation (&ChangeMaskSizeFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL); else change = (ObjectOperation (&ChangeClearSizeFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the thermal of the passed object. * * \return True if anything is changed. * */ bool ChangeObjectThermal (int Type, void *Ptr1, void *Ptr2, void *Ptr3, int therm_type) { bool change; Value = Absolute = therm_type; change = (ObjectOperation (&ChangeThermalFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the thermal of the passed object. * * \return True if anything is changed. * */ bool ChangeObjectViaLayers (void *Ptr1, void *Ptr2, void *Ptr3, int from, int to) { bool change = false; PinType *via = (PinType *) Ptr1; int new_from = (from != -1)?from:via->BuriedFrom; int new_to = (to != -1)?to:via->BuriedTo; int i; if (TEST_FLAG (LOCKFLAG, via)) return (NULL); if ((new_from == new_to) && new_from != 0) return false; /* special case - changing TH via "from" layer sets "to" layer to bottom layer */ if (!VIA_IS_BURIED (via) && (to == -1)) new_to = GetMaxBottomLayer (); for (i=0; i < max_copper_layer; i++) { /* AddObjectToClearPolyUndoList (VIA_TYPE, &(PCB->Data->Layer[i]), via, via, false); not needed? */ RestoreToPolygon (PCB->Data, VIA_TYPE, &(PCB->Data->Layer[i]), via); } if (from != -1 || to != -1) { AddObjectToSetViaLayersUndoList (via, via, via); change = true; } via->BuriedFrom = new_from; via->BuriedTo = new_to; if (VIA_IS_BURIED (via)) { SanitizeBuriedVia (via); for (i=0; i < max_copper_layer; i++) { /* AddObjectToClearPolyUndoList (VIA_TYPE, &(PCB->Data->Layer[i]), via, via, true); not needed? */ ClearFromPolygon (PCB->Data, VIA_TYPE, &(PCB->Data->Layer[i]), via); } DrawVia (via); } if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the 2nd size of the passed object. * * \return True if anything is changed. */ bool ChangeObject2ndSize (int Type, void *Ptr1, void *Ptr2, void *Ptr3, Coord Difference, bool fixIt, bool incundo) { bool change; /* setup identifier */ Absolute = (fixIt) ? 1 : 0; Value = Difference; change = (ObjectOperation (&Change2ndSizeFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL); if (change) { Draw (); if (incundo) IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the mask size of the passed object. * * \return True if anything is changed. */ bool ChangeObjectMaskSize (int Type, void *Ptr1, void *Ptr2, void *Ptr3, Coord Difference, bool fixIt) { bool change; /* setup identifier */ Absolute = (fixIt) ? 1 : 0; Value = Difference; change = (ObjectOperation (&ChangeMaskSizeFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL); if (change) { Draw (); IncrementUndoSerialNumber (); } return (change); } /*! * \brief Changes the name of the passed object. * * \warning The allocated memory isn't freed because the old string is used * by the undo module. * * \return The old name. */ void * ChangeObjectName (int Type, void *Ptr1, void *Ptr2, void *Ptr3, char *Name) { void *result; /* setup identifier */ NewName = Name; result = ObjectOperation (&ChangeNameFunctions, Type, Ptr1, Ptr2, Ptr3); Draw (); return (result); } /*! * \brief Changes the clearance-flag of the passed object. * * \return True if anything is changed. */ bool ChangeObjectJoin (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&ChangeJoinFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Sets the clearance-flag of the passed object. * * \return True if anything is changed. */ bool SetObjectJoin (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&SetJoinFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Clears the clearance-flag of the passed object. * * \return True if anything is changed. */ bool ClrObjectJoin (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&ClrJoinFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Changes the square-flag of the passed object. * * \return True if anything is changed. */ bool ChangeObjectSquare (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&ChangeSquareFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Sets the square-flag of the passed object. * * \return True if anything is changed. */ bool SetObjectSquare (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&SetSquareFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Clears the square-flag of the passed object. * * \return True if anything is changed. */ bool ClrObjectSquare (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&ClrSquareFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Changes the octagon-flag of the passed object. * * \return True if anything is changed. */ bool ChangeObjectOctagon (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&ChangeOctagonFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Sets the octagon-flag of the passed object. * * \return True if anything is changed. */ bool SetObjectOctagon (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&SetOctagonFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \brief Clears the octagon-flag of the passed object. * * \return True if anything is changed. */ bool ClrObjectOctagon (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { if (ObjectOperation (&ClrOctagonFunctions, Type, Ptr1, Ptr2, Ptr3) != NULL) { Draw (); IncrementUndoSerialNumber (); return (true); } return (false); } /*! * \bief Queries the user for a new object name and changes it. * * \warning The allocated memory isn't freed because the old string is used * by the undo module. */ void * QueryInputAndChangeObjectName (int Type, void *Ptr1, void *Ptr2, void *Ptr3) { char *name = NULL; char msg[513]; /* if passed an element name, make it an element reference instead */ if (Type == ELEMENTNAME_TYPE) { Type = ELEMENT_TYPE; Ptr2 = Ptr1; Ptr3 = Ptr1; } switch (Type) { case LINE_TYPE: name = gui->prompt_for (_("Linename:"), EMPTY (((LineType *) Ptr2)->Number)); break; case VIA_TYPE: name = gui->prompt_for (_("Vianame:"), EMPTY (((PinType *) Ptr2)->Name)); break; case PIN_TYPE: sprintf (msg, _("%s Pin Name:"), EMPTY (((PinType *) Ptr2)->Number)); name = gui->prompt_for (msg, EMPTY (((PinType *) Ptr2)->Name)); break; case PAD_TYPE: sprintf (msg, _("%s Pad Name:"), EMPTY (((PadType *) Ptr2)->Number)); name = gui->prompt_for (msg, EMPTY (((PadType *) Ptr2)->Name)); break; case TEXT_TYPE: name = gui->prompt_for (_("Enter text:"), EMPTY (((TextType *) Ptr2)->TextString)); break; case ELEMENT_TYPE: name = gui->prompt_for (_("Elementname:"), EMPTY (ELEMENT_NAME (PCB, (ElementType *) Ptr2))); break; } if (name) { /* NB: ChangeObjectName takes ownership of the passed memory */ char *old = (char *)ChangeObjectName (Type, Ptr1, Ptr2, Ptr3, name); if (old != (char *) -1) { AddObjectToChangeNameUndoList (Type, Ptr1, Ptr2, Ptr3, old); IncrementUndoSerialNumber (); } Draw (); return (Ptr3); } return (NULL); } /*! * \brief Changes the maximum size of a layout, adjusts the scrollbars, * releases the saved pixmap if necessary and adjusts the cursor * confinement box. */ void ChangePCBSize (Coord Width, Coord Height) { PCB->MaxWidth = Width; PCB->MaxHeight = Height; hid_action ("PCBChanged"); } /*! * \brief Changes the mask size of a pad. * * \return TRUE if changed. */ static void * ChangePadMaskSize (ElementType *Element, PadType *Pad) { Coord new_value = (Absolute) ? Value : Pad->Mask + Value; new_value = MAX (new_value, 0); if (new_value == Pad->Mask && Absolute == 0) new_value = Pad->Thickness; if (new_value != Pad->Mask) { AddObjectToMaskSizeUndoList (PAD_TYPE, Element, Pad, Pad); ErasePad (Pad); r_delete_entry (PCB->Data->pad_tree, &Pad->BoundingBox); Pad->Mask = new_value; SetElementBoundingBox (PCB->Data, Element, &PCB->Font); DrawPad (Pad); return (Pad); } return (NULL); } /*! * \brief Changes the mask size of a pin. * * \return TRUE if changed. */ static void * ChangePinMaskSize (ElementType *Element, PinType *Pin) { Coord new_value = (Absolute) ? Value : Pin->Mask + Value; new_value = MAX (new_value, 0); if (new_value == Pin->Mask && Absolute == 0) new_value = Pin->Thickness; if (new_value != Pin->Mask) { AddObjectToMaskSizeUndoList (PIN_TYPE, Element, Pin, Pin); ErasePin (Pin); r_delete_entry (PCB->Data->pin_tree, &Pin->BoundingBox); Pin->Mask = new_value; SetElementBoundingBox (PCB->Data, Element, &PCB->Font); DrawPin (Pin); return (Pin); } return (NULL); } /*! * \brief Changes the mask size of a via. * * \return TRUE if changed. */ static void * ChangeViaMaskSize (PinType *Via) { Coord new_value; new_value = (Absolute) ? Value : Via->Mask + Value; new_value = MAX (new_value, 0); if (new_value != Via->Mask) { AddObjectToMaskSizeUndoList (VIA_TYPE, Via, Via, Via); EraseVia (Via); r_delete_entry (PCB->Data->via_tree, &Via->BoundingBox); Via->Mask = new_value; SetPinBoundingBox (Via); r_insert_entry (PCB->Data->via_tree, &Via->BoundingBox, 0); DrawVia (Via); return (Via); } return (NULL); } pcb-4.2.2/src/toporouter.h0000664000076400007640000003107613434555140012413 00000000000000/*! * \file src/toporouter.h * * \brief Topological Autorouter for PCB. * *
* *

Copyright.

\n * * Topological Autorouter for * PCB, interactive printed circuit board design * * Copyright (C) 2009 Anthony Blake * * Copyright (C) 2009-2011 PCB Contributors (see ChangeLog for details) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for email: * Anthony Blake, tonyb33@gmail.com */ #ifndef PCB_TOPOROUTER_H #define PCB_TOPOROUTER_H #include #include "data.h" #include "macro.h" #include "autoroute.h" #include "box.h" #include "create.h" #include "draw.h" #include "error.h" #include "find.h" #include "heap.h" #include "rtree.h" #include "misc.h" #include "mymem.h" #include "polygon.h" #include "rats.h" #include "remove.h" #include "thermal.h" #include "undo.h" #include "global.h" #include "gts.h" #include #include #include #define TOPOROUTER_FLAG_VERBOSE (1<<0) #define TOPOROUTER_FLAG_HARDDEST (1<<1) #define TOPOROUTER_FLAG_HARDSRC (1<<2) #define TOPOROUTER_FLAG_MATCH (1<<3) #define TOPOROUTER_FLAG_LAYERHINT (1<<4) #define TOPOROUTER_FLAG_LEASTINVALID (1<<5) #define TOPOROUTER_FLAG_AFTERORDER (1<<6) #define TOPOROUTER_FLAG_AFTERRUBIX (1<<7) #define TOPOROUTER_FLAG_GOFAR (1<<8) #define TOPOROUTER_FLAG_DETOUR (1<<9) #if TOPO_OUTPUT_ENABLED #include #endif #define EPSILON 0.0001f //#define DEBUG_ROAR 1 #define tvdistance(a,b) hypot(vx(a)-vx(b),vy(a)-vy(b)) #define edge_v1(e) (GTS_SEGMENT(e)->v1) #define edge_v2(e) (GTS_SEGMENT(e)->v2) #define tedge_v1(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v1)) #define tedge_v2(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v2)) #define tedge(v1,v2) TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v1), GTS_VERTEX(v2))) #define edge_routing(e) (TOPOROUTER_IS_CONSTRAINT(e) ? TOPOROUTER_CONSTRAINT(e)->routing : e->routing) #define vrouting(v) (edge_routing(v->routingedge)) #define edge_routing_next(e,list) ((list->next) ? TOPOROUTER_VERTEX(list->next->data) : TOPOROUTER_VERTEX(edge_v2(e))) #define edge_routing_prev(e,list) ((list->prev) ? TOPOROUTER_VERTEX(list->prev->data) : TOPOROUTER_VERTEX(edge_v1(e))) #define vx(v) (GTS_POINT(v)->x) #define vy(v) (GTS_POINT(v)->y) #define vz(v) (GTS_POINT(v)->z) #define close_enough_xy(a,b) (vx(a) > vx(b) - EPSILON && vx(a) < vx(b) + EPSILON && vy(a) > vy(b) - EPSILON && vy(a) < vy(b) + EPSILON) #define tev1x(e) (vx(tedge_v1(e)) #define tev1y(e) (vy(tedge_v1(e)) #define tev1z(e) (vz(tedge_v1(e)) #define tev2x(e) (vx(tedge_v2(e)) #define tev2y(e) (vy(tedge_v2(e)) #define tev2z(e) (vz(tedge_v2(e)) #define tvertex_intersect(a,b,c,d) (TOPOROUTER_VERTEX(vertex_intersect(GTS_VERTEX(a),GTS_VERTEX(b),GTS_VERTEX(c),GTS_VERTEX(d)))) #define TOPOROUTER_IS_BBOX(obj) (gts_object_is_from_class (obj, toporouter_bbox_class ())) #define TOPOROUTER_BBOX(obj) GTS_OBJECT_CAST (obj, toporouter_bbox_t, toporouter_bbox_class ()) #define TOPOROUTER_BBOX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_bbox_class_t, toporouter_bbox_class ()) typedef enum { PAD, PIN, VIA, ARC, VIA_SHADOW, LINE, OTHER, BOARD, EXPANSION_AREA, POLYGON, TEMP } toporouter_term_t; struct _toporouter_bbox_t { GtsBBox b; toporouter_term_t type; void *data; int layer; GtsSurface *surface; GtsTriangle *enclosing; GList *constraints; GtsPoint *point, *realpoint; // char *netlist, *style; struct _toporouter_cluster_t *cluster; }; struct _toporouter_bbox_class_t { GtsBBoxClass parent_class; }; typedef struct _toporouter_bbox_t toporouter_bbox_t; typedef struct _toporouter_bbox_class_t toporouter_bbox_class_t; #define TOPOROUTER_IS_EDGE(obj) (gts_object_is_from_class (obj, toporouter_edge_class ())) #define TOPOROUTER_EDGE(obj) GTS_OBJECT_CAST (obj, toporouter_edge_t, toporouter_edge_class ()) #define TOPOROUTER_EDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_edge_class_t, toporouter_edge_class ()) #define EDGE_FLAG_DIRECTCONNECTION (1<<0) struct _toporouter_edge_t { GtsEdge e; //NetListType *netlist; guint flags; GList *routing; }; struct _toporouter_edge_class_t { GtsEdgeClass parent_class; }; typedef struct _toporouter_edge_t toporouter_edge_t; typedef struct _toporouter_edge_class_t toporouter_edge_class_t; #define TOPOROUTER_IS_VERTEX(obj) (gts_object_is_from_class (obj, toporouter_vertex_class ())) #define TOPOROUTER_VERTEX(obj) GTS_OBJECT_CAST (obj, toporouter_vertex_t, toporouter_vertex_class ()) #define TOPOROUTER_VERTEX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_vertex_class_t, toporouter_vertex_class ()) #define VERTEX_FLAG_VIZ (1<<1) #define VERTEX_FLAG_CCW (1<<2) #define VERTEX_FLAG_CW (1<<3) #define VERTEX_FLAG_RED (1<<4) #define VERTEX_FLAG_GREEN (1<<5) #define VERTEX_FLAG_BLUE (1<<6) #define VERTEX_FLAG_TEMP (1<<7) #define VERTEX_FLAG_ROUTE (1<<8) #define VERTEX_FLAG_FAKE (1<<10) #define VERTEX_FLAG_SPECCUT (1<<11) struct _toporouter_vertex_t { GtsVertex v; //GList *boxes; struct _toporouter_bbox_t *bbox; struct _toporouter_vertex_t *parent; struct _toporouter_vertex_t *child; toporouter_edge_t *routingedge; guint flags; gdouble gcost, hcost; guint gn; struct _toporouter_arc_t *arc; struct _toporouter_oproute_t *oproute; struct _toporouter_route_t *route; gdouble thickness; }; struct _toporouter_vertex_class_t { GtsVertexClass parent_class; }; typedef struct _toporouter_vertex_t toporouter_vertex_t; typedef struct _toporouter_vertex_class_t toporouter_vertex_class_t; #define TOPOROUTER_IS_CONSTRAINT(obj) (gts_object_is_from_class (obj, toporouter_constraint_class ())) #define TOPOROUTER_CONSTRAINT(obj) GTS_OBJECT_CAST (obj, toporouter_constraint_t, toporouter_constraint_class ()) #define TOPOROUTER_CONSTRAINT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_constraint_class_t, toporouter_constraint_class ()) struct _toporouter_constraint_t { GtsConstraint c; toporouter_bbox_t *box; GList *routing; }; struct _toporouter_constraint_class_t { GtsConstraintClass parent_class; }; typedef struct { gdouble x, y; } toporouter_spoint_t; typedef struct _toporouter_constraint_t toporouter_constraint_t; typedef struct _toporouter_constraint_class_t toporouter_constraint_class_t; typedef struct { GtsSurface *surface; // GtsTriangle *t; // GtsVertex *v1, *v2, *v3; GList *vertices; GList *constraints; GList *edges; } toporouter_layer_t; #define TOPOROUTER_VERTEX_REGION(x) ((toporouter_vertex_region_t *)x) typedef struct { GList *points; toporouter_vertex_t *v1, *v2; toporouter_vertex_t *origin; } toporouter_vertex_region_t; struct _toporouter_rubberband_arc_t { toporouter_vertex_t *pathv, *arcv; gdouble r, d; gint wind; GList *list; }; typedef struct _toporouter_rubberband_arc_t toporouter_rubberband_arc_t; #define TOPOROUTER_RUBBERBAND_ARC(x) ((toporouter_rubberband_arc_t *)x) struct _toporouter_route_t { struct _toporouter_netlist_t *netlist; struct _toporouter_cluster_t *src, *dest; struct _toporouter_cluster_t *psrc, *pdest; gdouble score, detourscore; toporouter_vertex_t *curpoint; GHashTable *alltemppoints; GList *path; guint flags; GList *destvertices, *srcvertices; GList *topopath; gdouble pscore; GList *ppath; gint *ppathindices; }; typedef struct _toporouter_route_t toporouter_route_t; #define TOPOROUTER_ROUTE(x) ((toporouter_route_t *)x) struct _toporouter_netlist_t { GPtrArray *clusters, *routes; char *netlist, *style; GList *routed; struct _toporouter_netlist_t *pair; }; typedef struct _toporouter_netlist_t toporouter_netlist_t; #define TOPOROUTER_NETLIST(x) ((toporouter_netlist_t *)x) struct _toporouter_cluster_t { gint c, pc; GPtrArray *boxes; toporouter_netlist_t *netlist; }; typedef struct _toporouter_cluster_t toporouter_cluster_t; #define TOPOROUTER_CLUSTER(x) ((toporouter_cluster_t *)x) #define TOPOROUTER_OPROUTE(x) ((toporouter_oproute_t *)x) #define oproute_next(a,b) (b->next ? TOPOROUTER_ARC(b->next->data) : a->term2) #define oproute_prev(a,b) (b->prev ? TOPOROUTER_ARC(b->prev->data) : a->term1) #define TOPOROUTER_SERPINTINE(x) ((toporouter_serpintine_t *)x) struct _toporouter_serpintine_t { GList *arcs; gdouble x, y; gdouble x0, y0, x1, y1; gpointer start; gdouble halfa, radius; guint nhalfcycles; }; typedef struct _toporouter_serpintine_t toporouter_serpintine_t; struct _toporouter_oproute_t { GList *arcs; toporouter_vertex_t *term1, *term2; char *style; char *netlist; guint layergroup; gdouble tof; GList *path; toporouter_serpintine_t *serp; }; typedef struct _toporouter_oproute_t toporouter_oproute_t; #define TOPOROUTER_IS_ARC(obj) (gts_object_is_from_class (obj, toporouter_arc_class())) #define TOPOROUTER_ARC(obj) GTS_OBJECT_CAST (obj, toporouter_arc_t, toporouter_arc_class()) #define TOPOROUTER_ARC_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_arc_class_t, toporouter_arc_class()) struct _toporouter_arc_t { GtsObject object; gdouble x0, y0, x1, y1; toporouter_vertex_t *centre, *v; gdouble r; gint dir; GList *clearance; toporouter_oproute_t *oproute; toporouter_vertex_t *v1, *v2; }; struct _toporouter_arc_class_t { GtsObjectClass parent_class; gboolean binary; }; typedef struct _toporouter_arc_t toporouter_arc_t; typedef struct _toporouter_arc_class_t toporouter_arc_class_t; typedef struct _toporouter_t toporouter_t; typedef struct { guint id; guint *pairwise_nodetour; gdouble pairwise_detour_sum; gdouble score; guint pairwise_fails; toporouter_route_t *routedata; toporouter_t *r; } toporouter_netscore_t; #define TOPOROUTER_NETSCORE(x) ((toporouter_netscore_t *)x) struct _toporouter_t { GSList *bboxes; GNode *bboxtree; toporouter_layer_t *layers; GList *paths; GList *keepoutlayers; guint flags; GList *destboxes, *consumeddestboxes; /* settings: */ gdouble viacost; gdouble wiring_score; GPtrArray *routes; GPtrArray *netlists; GList *routednets, *failednets; gint (*netsort)(toporouter_netscore_t **, toporouter_netscore_t **); struct timeval starttime; FILE *debug; }; typedef gint (*oproute_adjseg_func) (toporouter_t *, GList **, GList **, guint *, gdouble, gdouble, gdouble, gdouble, toporouter_oproute_t *, toporouter_oproute_t *); typedef struct { #ifdef CAIRO_H cairo_t *cr; cairo_surface_t *surface; #endif double s; /*!< scale factor. */ int mode; void *data; char *filename; double iw; /*!< image width dimensions. */ double ih; /*!< image height dimensions. */ } drawing_context_t; #define FOREACH_CLUSTER(clusters) do { \ for(toporouter_cluster_t **i = ((toporouter_cluster_t **)clusters->pdata) + clusters->len - 1; i >= (toporouter_cluster_t **)clusters->pdata && clusters->len > 0; --i) { \ toporouter_cluster_t *cluster = *i; #define FOREACH_BBOX(boxes) do { \ for(toporouter_bbox_t **i = ((toporouter_bbox_t **)boxes->pdata) + boxes->len - 1; i >= (toporouter_bbox_t **)boxes->pdata && boxes->len > 0; --i) { \ toporouter_bbox_t *box = *i; #define FOREACH_ROUTE(routes) do { \ for(toporouter_route_t **i = ((toporouter_route_t **)routes->pdata) + routes->len - 1; i >= (toporouter_route_t **)routes->pdata && routes->len > 0; --i) { \ toporouter_route_t *routedata = *i; #define FOREACH_NETSCORE(netscores) do { \ for(toporouter_netscore_t **i = ((toporouter_netscore_t **)netscores->pdata) + netscores->len - 1; i >= (toporouter_netscore_t **)netscores->pdata && netscores->len > 0; --i) { \ toporouter_netscore_t *netscore = *i; #define FOREACH_NETLIST(netlists) do { \ for(toporouter_netlist_t **i = ((toporouter_netlist_t **)netlists->pdata) + netlists->len - 1; i >= (toporouter_netlist_t **)netlists->pdata && netlists->len > 0; --i) { \ toporouter_netlist_t *netlist = *i; #define FOREACH_END }} while(0) #endif /* PCB_TOPOROUTER_H */ pcb-4.2.2/src/default_font0000664000076400007640000003423012575072760012417 00000000000000Symbol(' ' 18) ( ) Symbol('!' 12) ( SymbolLine(0 35 0 40 8) SymbolLine(0 0 0 25 8) ) Symbol('"' 12) ( SymbolLine(0 0 0 10 8) SymbolLine(10 0 10 10 8) ) Symbol('#' 12) ( SymbolLine(0 25 20 25 8) SymbolLine(0 15 20 15 8) SymbolLine(15 10 15 30 8) SymbolLine(5 10 5 30 8) ) Symbol('$' 12) ( SymbolLine(15 5 20 10 8) SymbolLine(5 5 15 5 8) SymbolLine(0 10 5 5 8) SymbolLine(0 10 0 15 8) SymbolLine(0 15 5 20 8) SymbolLine(5 20 15 20 8) SymbolLine(15 20 20 25 8) SymbolLine(20 25 20 30 8) SymbolLine(15 35 20 30 8) SymbolLine(5 35 15 35 8) SymbolLine(0 30 5 35 8) SymbolLine(10 0 10 40 8) ) Symbol('%' 12) ( SymbolLine(0 5 0 10 8) SymbolLine(0 5 5 0 8) SymbolLine(5 0 10 0 8) SymbolLine(10 0 15 5 8) SymbolLine(15 5 15 10 8) SymbolLine(10 15 15 10 8) SymbolLine(5 15 10 15 8) SymbolLine(0 10 5 15 8) SymbolLine(0 40 40 0 8) SymbolLine(35 40 40 35 8) SymbolLine(40 30 40 35 8) SymbolLine(35 25 40 30 8) SymbolLine(30 25 35 25 8) SymbolLine(25 30 30 25 8) SymbolLine(25 30 25 35 8) SymbolLine(25 35 30 40 8) SymbolLine(30 40 35 40 8) ) Symbol('&' 12) ( SymbolLine(0 35 5 40 8) SymbolLine(0 5 0 15 8) SymbolLine(0 5 5 0 8) SymbolLine(0 25 15 10 8) SymbolLine(5 40 10 40 8) SymbolLine(10 40 20 30 8) SymbolLine(0 15 25 40 8) SymbolLine(5 0 10 0 8) SymbolLine(10 0 15 5 8) SymbolLine(15 5 15 10 8) SymbolLine(0 25 0 35 8) ) Symbol(''' 12) ( SymbolLine(0 10 10 0 8) ) Symbol('(' 12) ( SymbolLine(0 35 5 40 8) SymbolLine(0 5 5 0 8) SymbolLine(0 5 0 35 8) ) Symbol(')' 12) ( SymbolLine(0 0 5 5 8) SymbolLine(5 5 5 35 8) SymbolLine(0 40 5 35 8) ) Symbol('*' 12) ( SymbolLine(0 10 20 30 8) SymbolLine(0 30 20 10 8) SymbolLine(0 20 20 20 8) SymbolLine(10 10 10 30 8) ) Symbol('+' 12) ( SymbolLine(0 20 20 20 8) SymbolLine(10 10 10 30 8) ) Symbol(',' 12) ( SymbolLine(0 50 10 40 8) ) Symbol('-' 12) ( SymbolLine(0 20 20 20 8) ) Symbol('.' 12) ( SymbolLine(0 40 5 40 8) ) Symbol('/' 12) ( SymbolLine(0 35 30 5 8) ) Symbol('0' 12) ( SymbolLine(0 35 5 40 8) SymbolLine(0 5 0 35 8) SymbolLine(0 5 5 0 8) SymbolLine(5 0 15 0 8) SymbolLine(15 0 20 5 8) SymbolLine(20 5 20 35 8) SymbolLine(15 40 20 35 8) SymbolLine(5 40 15 40 8) SymbolLine(0 30 20 10 8) ) Symbol('1' 12) ( SymbolLine( 0 8 8 0 8) SymbolLine( 8 0 8 40 8) SymbolLine( 0 40 15 40 8) ) Symbol('2' 12) ( SymbolLine(0 5 5 0 8) SymbolLine(5 0 20 0 8) SymbolLine(20 0 25 5 8) SymbolLine(25 5 25 15 8) SymbolLine(0 40 25 15 8) SymbolLine(0 40 25 40 8) ) Symbol('3' 12) ( SymbolLine( 0 5 5 0 8) SymbolLine( 5 0 15 0 8) SymbolLine(15 0 20 5 8) SymbolLine(15 40 20 35 8) SymbolLine( 5 40 15 40 8) SymbolLine( 0 35 5 40 8) SymbolLine( 5 18 15 18 8) SymbolLine(20 5 20 13 8) SymbolLine(20 23 20 35 8) SymbolLine(20 23 15 18 8) SymbolLine(20 13 15 18 8) ) Symbol('4' 12) ( SymbolLine(0 25 20 0 8) SymbolLine(0 25 25 25 8) SymbolLine(20 0 20 40 8) ) Symbol('5' 12) ( SymbolLine(0 0 20 0 8) SymbolLine(0 0 0 20 8) SymbolLine(0 20 5 15 8) SymbolLine(5 15 15 15 8) SymbolLine(15 15 20 20 8) SymbolLine(20 20 20 35 8) SymbolLine(15 40 20 35 8) SymbolLine(5 40 15 40 8) SymbolLine(0 35 5 40 8) ) Symbol('6' 12) ( SymbolLine(15 0 20 5 8) SymbolLine( 5 0 15 0 8) SymbolLine( 0 5 5 0 8) SymbolLine( 0 5 0 35 8) SymbolLine( 0 35 5 40 8) SymbolLine(15 18 20 23 8) SymbolLine( 0 18 15 18 8) SymbolLine( 5 40 15 40 8) SymbolLine(15 40 20 35 8) SymbolLine(20 23 20 35 8) ) Symbol('7' 12) ( SymbolLine( 5 40 25 0 8) SymbolLine( 0 0 25 0 8) ) Symbol('8' 12) ( SymbolLine( 0 35 5 40 8) SymbolLine( 0 27 0 35 8) SymbolLine( 0 27 7 20 8) SymbolLine( 7 20 13 20 8) SymbolLine(13 20 20 27 8) SymbolLine(20 27 20 35 8) SymbolLine(15 40 20 35 8) SymbolLine( 5 40 15 40 8) SymbolLine( 0 13 7 20 8) SymbolLine( 0 5 0 13 8) SymbolLine( 0 5 5 0 8) SymbolLine( 5 0 15 0 8) SymbolLine(15 0 20 5 8) SymbolLine(20 5 20 13 8) SymbolLine(13 20 20 13 8) ) Symbol('9' 12) ( SymbolLine(5 40 20 20 8) SymbolLine(20 5 20 20 8) SymbolLine(15 0 20 5 8) SymbolLine(5 0 15 0 8) SymbolLine(0 5 5 0 8) SymbolLine(0 5 0 15 8) SymbolLine(0 15 5 20 8) SymbolLine(5 20 20 20 8) ) Symbol(':' 12) ( SymbolLine(0 15 5 15 8) SymbolLine(0 25 5 25 8) ) Symbol(';' 12) ( SymbolLine(0 40 10 30 8) SymbolLine(10 15 10 20 8) ) Symbol('<' 12) ( SymbolLine(0 20 10 10 8) SymbolLine(0 20 10 30 8) ) Symbol('=' 12) ( SymbolLine(0 15 20 15 8) SymbolLine(0 25 20 25 8) ) Symbol('>' 12) ( SymbolLine(0 10 10 20 8) SymbolLine(0 30 10 20 8) ) Symbol('?' 12) ( SymbolLine(10 20 10 25 8) SymbolLine(10 35 10 40 8) SymbolLine(0 5 0 10 8) SymbolLine(0 5 5 0 8) SymbolLine(5 0 15 0 8) SymbolLine(15 0 20 5 8) SymbolLine(20 5 20 10 8) SymbolLine(10 20 20 10 8) ) Symbol('A' 12) ( SymbolLine( 0 10 0 40 8) SymbolLine( 0 10 7 0 8) SymbolLine( 7 0 18 0 8) SymbolLine(18 0 25 10 8) SymbolLine(25 10 25 40 8) SymbolLine( 0 20 25 20 8) ) Symbol('B' 12) ( SymbolLine( 0 40 20 40 8) SymbolLine(20 40 25 35 8) SymbolLine(25 23 25 35 8) SymbolLine(20 18 25 23 8) SymbolLine( 5 18 20 18 8) SymbolLine( 5 0 5 40 8) SymbolLine( 0 0 20 0 8) SymbolLine(20 0 25 5 8) SymbolLine(25 5 25 13 8) SymbolLine(20 18 25 13 8) ) Symbol('C' 12) ( SymbolLine(7 40 20 40 8) SymbolLine(0 33 7 40 8) SymbolLine(0 7 0 33 8) SymbolLine(0 7 7 0 8) SymbolLine(7 0 20 0 8) ) Symbol('D' 12) ( SymbolLine( 5 0 5 40 8) SymbolLine(18 0 25 7 8) SymbolLine(25 7 25 33 8) SymbolLine(18 40 25 33 8) SymbolLine( 0 40 18 40 8) SymbolLine( 0 0 18 0 8) ) Symbol('E' 12) ( SymbolLine(0 18 15 18 8) SymbolLine(0 40 20 40 8) SymbolLine(0 0 0 40 8) SymbolLine(0 0 20 0 8) ) Symbol('F' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 0 20 0 8) SymbolLine(0 18 15 18 8) ) Symbol('G' 12) ( SymbolLine(20 0 25 5 8) SymbolLine(5 0 20 0 8) SymbolLine(0 5 5 0 8) SymbolLine(0 5 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 20 40 8) SymbolLine(20 40 25 35 8) SymbolLine(25 25 25 35 8) SymbolLine(20 20 25 25 8) SymbolLine(10 20 20 20 8) ) Symbol('H' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(25 0 25 40 8) SymbolLine(0 20 25 20 8) ) Symbol('I' 12) ( SymbolLine(0 0 10 0 8) SymbolLine(5 0 5 40 8) SymbolLine(0 40 10 40 8) ) Symbol('J' 12) ( SymbolLine( 7 0 15 0 8) SymbolLine(15 0 15 35 8) SymbolLine(10 40 15 35 8) SymbolLine( 5 40 10 40 8) SymbolLine( 0 35 5 40 8) SymbolLine( 0 35 0 30 8) ) Symbol('K' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 20 20 0 8) SymbolLine(0 20 20 40 8) ) Symbol('L' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 40 20 40 8) ) Symbol('M' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 0 15 20 8) SymbolLine(15 20 30 0 8) SymbolLine(30 0 30 40 8) ) Symbol('N' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 0 25 40 8) SymbolLine(25 0 25 40 8) ) Symbol('O' 12) ( SymbolLine(0 5 0 35 8) SymbolLine(0 5 5 0 8) SymbolLine(5 0 15 0 8) SymbolLine(15 0 20 5 8) SymbolLine(20 5 20 35 8) SymbolLine(15 40 20 35 8) SymbolLine(5 40 15 40 8) SymbolLine(0 35 5 40 8) ) Symbol('P' 12) ( SymbolLine(5 0 5 40 8) SymbolLine(0 0 20 0 8) SymbolLine(20 0 25 5 8) SymbolLine(25 5 25 15 8) SymbolLine(20 20 25 15 8) SymbolLine(5 20 20 20 8) ) Symbol('Q' 12) ( SymbolLine( 0 5 0 35 8) SymbolLine( 0 5 5 0 8) SymbolLine( 5 0 15 0 8) SymbolLine(15 0 20 5 8) SymbolLine(20 5 20 30 8) SymbolLine(10 40 20 30 8) SymbolLine( 5 40 10 40 8) SymbolLine( 0 35 5 40 8) SymbolLine(10 25 20 40 8) ) Symbol('R' 12) ( SymbolLine( 0 0 20 0 8) SymbolLine(20 0 25 5 8) SymbolLine(25 5 25 15 8) SymbolLine(20 20 25 15 8) SymbolLine( 5 20 20 20 8) SymbolLine( 5 0 5 40 8) SymbolLine(13 20 25 40 8) ) Symbol('S' 12) ( SymbolLine(20 0 25 5 8) SymbolLine(5 0 20 0 8) SymbolLine(0 5 5 0 8) SymbolLine(0 5 0 15 8) SymbolLine(0 15 5 20 8) SymbolLine(5 20 20 20 8) SymbolLine(20 20 25 25 8) SymbolLine(25 25 25 35 8) SymbolLine(20 40 25 35 8) SymbolLine(5 40 20 40 8) SymbolLine(0 35 5 40 8) ) Symbol('T' 12) ( SymbolLine(0 0 20 0 8) SymbolLine(10 0 10 40 8) ) Symbol('U' 12) ( SymbolLine(0 0 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 15 40 8) SymbolLine(15 40 20 35 8) SymbolLine(20 0 20 35 8) ) Symbol('V' 12) ( SymbolLine( 0 0 10 40 8) SymbolLine(10 40 20 0 8) ) Symbol('W' 12) ( SymbolLine( 0 0 0 20 8) SymbolLine( 0 20 5 40 8) SymbolLine( 5 40 15 20 8) SymbolLine(15 20 25 40 8) SymbolLine(25 40 30 20 8) SymbolLine(30 20 30 0 8) ) Symbol('X' 12) ( SymbolLine( 0 40 25 0 8) SymbolLine( 0 0 25 40 8) ) Symbol('Y' 12) ( SymbolLine( 0 0 10 20 8) SymbolLine(10 20 20 0 8) SymbolLine(10 20 10 40 8) ) Symbol('Z' 12) ( SymbolLine( 0 0 25 0 8) SymbolLine( 0 40 25 0 8) SymbolLine( 0 40 25 40 8) ) Symbol('[' 12) ( SymbolLine(0 0 5 0 8) SymbolLine(0 0 0 40 8) SymbolLine(0 40 5 40 8) ) Symbol('\' 12) ( SymbolLine(0 5 30 35 8) ) Symbol(']' 12) ( SymbolLine(0 0 5 0 8) SymbolLine(5 0 5 40 8) SymbolLine(0 40 5 40 8) ) Symbol('^' 12) ( SymbolLine(0 5 5 0 8) SymbolLine(5 0 10 5 8) ) Symbol('_' 12) ( SymbolLine(0 40 20 40 8) ) Symbol('a' 12) ( SymbolLine(15 20 20 25 8) SymbolLine(5 20 15 20 8) SymbolLine(0 25 5 20 8) SymbolLine(0 25 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(20 20 20 35 8) SymbolLine(20 35 25 40 8) SymbolLine(5 40 15 40 8) SymbolLine(15 40 20 35 8) ) Symbol('b' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 15 40 8) SymbolLine(15 40 20 35 8) SymbolLine(20 25 20 35 8) SymbolLine(15 20 20 25 8) SymbolLine(5 20 15 20 8) SymbolLine(0 25 5 20 8) ) Symbol('c' 12) ( SymbolLine(5 20 20 20 8) SymbolLine(0 25 5 20 8) SymbolLine(0 25 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 20 40 8) ) Symbol('d' 12) ( SymbolLine(20 0 20 40 8) SymbolLine(15 40 20 35 8) SymbolLine(5 40 15 40 8) SymbolLine(0 35 5 40 8) SymbolLine(0 25 0 35 8) SymbolLine(0 25 5 20 8) SymbolLine(5 20 15 20 8) SymbolLine(15 20 20 25 8) ) Symbol('e' 12) ( SymbolLine(5 40 20 40 8) SymbolLine(0 35 5 40 8) SymbolLine(0 25 0 35 8) SymbolLine(0 25 5 20 8) SymbolLine(5 20 15 20 8) SymbolLine(15 20 20 25 8) SymbolLine(0 30 20 30 8) SymbolLine(20 30 20 25 8) ) Symbol('f' 10) ( SymbolLine(5 5 5 40 8) SymbolLine(5 5 10 0 8) SymbolLine(10 0 15 0 8) SymbolLine(0 20 10 20 8) ) Symbol('g' 12) ( SymbolLine(15 20 20 25 8) SymbolLine(5 20 15 20 8) SymbolLine(0 25 5 20 8) SymbolLine(0 25 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 15 40 8) SymbolLine(15 40 20 35 8) SymbolLine(0 50 5 55 8) SymbolLine(5 55 15 55 8) SymbolLine(15 55 20 50 8) SymbolLine(20 20 20 50 8) ) Symbol('h' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 25 5 20 8) SymbolLine(5 20 15 20 8) SymbolLine(15 20 20 25 8) SymbolLine(20 25 20 40 8) ) Symbol('i' 10) ( SymbolLine(0 10 0 11 10) SymbolLine(0 25 0 40 8) ) Symbol('j' 10) ( SymbolLine(5 10 5 11 10) SymbolLine(5 25 5 50 8) SymbolLine(0 55 5 50 8) ) Symbol('k' 12) ( SymbolLine(0 0 0 40 8) SymbolLine(0 25 15 40 8) SymbolLine(0 25 10 15 8) ) Symbol('l' 10) ( SymbolLine(0 0 0 35 8) SymbolLine(0 35 5 40 8) ) Symbol('m' 12) ( SymbolLine(5 25 5 40 8) SymbolLine(5 25 10 20 8) SymbolLine(10 20 15 20 8) SymbolLine(15 20 20 25 8) SymbolLine(20 25 20 40 8) SymbolLine(20 25 25 20 8) SymbolLine(25 20 30 20 8) SymbolLine(30 20 35 25 8) SymbolLine(35 25 35 40 8) SymbolLine(0 20 5 25 8) ) Symbol('n' 12) ( SymbolLine(5 25 5 40 8) SymbolLine(5 25 10 20 8) SymbolLine(10 20 15 20 8) SymbolLine(15 20 20 25 8) SymbolLine(20 25 20 40 8) SymbolLine(0 20 5 25 8) ) Symbol('o' 12) ( SymbolLine(0 25 0 35 8) SymbolLine(0 25 5 20 8) SymbolLine(5 20 15 20 8) SymbolLine(15 20 20 25 8) SymbolLine(20 25 20 35 8) SymbolLine(15 40 20 35 8) SymbolLine(5 40 15 40 8) SymbolLine(0 35 5 40 8) ) Symbol('p' 12) ( SymbolLine(5 25 5 55 8) SymbolLine(0 20 5 25 8) SymbolLine(5 25 10 20 8) SymbolLine(10 20 20 20 8) SymbolLine(20 20 25 25 8) SymbolLine(25 25 25 35 8) SymbolLine(20 40 25 35 8) SymbolLine(10 40 20 40 8) SymbolLine(5 35 10 40 8) ) Symbol('q' 12) ( SymbolLine(20 25 20 55 8) SymbolLine(15 20 20 25 8) SymbolLine(5 20 15 20 8) SymbolLine(0 25 5 20 8) SymbolLine(0 25 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 15 40 8) SymbolLine(15 40 20 35 8) ) Symbol('r' 12) ( SymbolLine(5 25 5 40 8) SymbolLine(5 25 10 20 8) SymbolLine(10 20 20 20 8) SymbolLine(0 20 5 25 8) ) Symbol('s' 12) ( SymbolLine(5 40 20 40 8) SymbolLine(20 40 25 35 8) SymbolLine(20 30 25 35 8) SymbolLine(5 30 20 30 8) SymbolLine(0 25 5 30 8) SymbolLine(0 25 5 20 8) SymbolLine(5 20 20 20 8) SymbolLine(20 20 25 25 8) SymbolLine(0 35 5 40 8) ) Symbol('t' 10) ( SymbolLine(5 0 5 35 8) SymbolLine(5 35 10 40 8) SymbolLine(0 15 10 15 8) ) Symbol('u' 12) ( SymbolLine(0 20 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 15 40 8) SymbolLine(15 40 20 35 8) SymbolLine(20 20 20 35 8) ) Symbol('v' 12) ( SymbolLine( 0 20 10 40 8) SymbolLine(20 20 10 40 8) ) Symbol('w' 12) ( SymbolLine(0 20 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(5 40 10 40 8) SymbolLine(10 40 15 35 8) SymbolLine(15 20 15 35 8) SymbolLine(15 35 20 40 8) SymbolLine(20 40 25 40 8) SymbolLine(25 40 30 35 8) SymbolLine(30 20 30 35 8) ) Symbol('x' 12) ( SymbolLine(0 20 20 40 8) SymbolLine(0 40 20 20 8) ) Symbol('y' 12) ( SymbolLine(0 20 0 35 8) SymbolLine(0 35 5 40 8) SymbolLine(20 20 20 50 8) SymbolLine(15 55 20 50 8) SymbolLine(5 55 15 55 8) SymbolLine(0 50 5 55 8) SymbolLine(5 40 15 40 8) SymbolLine(15 40 20 35 8) ) Symbol('z' 12) ( SymbolLine(0 20 20 20 8) SymbolLine(0 40 20 20 8) SymbolLine(0 40 20 40 8) ) Symbol('{' 12) ( SymbolLine(5 5 10 0 8) SymbolLine(5 5 5 15 8) SymbolLine(0 20 5 15 8) SymbolLine(0 20 5 25 8) SymbolLine(5 25 5 35 8) SymbolLine(5 35 10 40 8) ) Symbol('|' 12) ( SymbolLine(0 0 0 40 8) ) Symbol('}' 12) ( SymbolLine(0 0 5 5 8) SymbolLine(5 5 5 15 8) SymbolLine(5 15 10 20 8) SymbolLine(5 25 10 20 8) SymbolLine(5 25 5 35 8) SymbolLine(0 40 5 35 8) ) Symbol('~' 12) ( SymbolLine(0 25 5 20 8) SymbolLine(5 20 10 20 8) SymbolLine(10 20 15 25 8) SymbolLine(15 25 20 25 8) SymbolLine(20 25 25 20 8) ) Symbol('@' 12) ( SymbolLine(0 0 0 30 8) SymbolLine(0 30 10 40 8) SymbolLine(10 40 40 40 8) SymbolLine(50 25 50 0 8) SymbolLine(50 0 40 -10 8) SymbolLine(40 -10 10 -10 8) SymbolLine(10 -10 0 0 8) SymbolLine(15 10 15 20 8) SymbolLine(15 20 20 25 8) SymbolLine(20 25 30 25 8) SymbolLine(30 25 35 20 8) SymbolLine(35 20 40 25 8) SymbolLine(35 20 35 5 8) SymbolLine(35 10 30 5 8) SymbolLine(20 5 30 5 8) SymbolLine(20 5 15 10 8) SymbolLine(40 25 50 25 8) ) pcb-4.2.2/src/layerflags.h0000664000076400007640000000262413434555140012317 00000000000000/*! * \file src/layerflags.h * * \brief Prototypes for changing layer flags. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2007 DJ Delorie * * Copyright (C) 2015 Markus "Traumflug" Hitter * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PCB_LAYERFLAGS_H #define PCB_LAYERFLAGS_H unsigned int string_to_layertype (const char *typestring, int (*error) (const char *msg)); const char *layertype_to_string (unsigned int type); unsigned int guess_layertype (const char *name, int layer_number, DataType *data); #endif /* PCB_LAYERFLAGS_H */ pcb-4.2.2/src/renumber.c0000664000076400007640000001072613434555140012002 00000000000000/*! * \file renumber.c * * \brief Renumber refdesses on pcb or in the buffer. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2006 DJ Delorie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "config.h" #include "global.h" #include "data.h" #include "hid.h" #include "misc.h" #include "create.h" #include "rtree.h" #include "undo.h" #include "error.h" #include "change.h" /* %start-doc actions RenumberBlock The @code{RenumberBlocks()} action renumbers all selected refdesses on the pcb. Usage: RenumberBlock(oldnum,newnum) All selected elements are renumbered by adding (newnum-oldnum) to the existing number. To invoke it, use the command window, usually by typing ":". Example: @code{RenumberBlock(100,200)} will change R213 to R313. %end-doc */ static int renumber_block (int argc, char **argv, Coord x, Coord y) { char num_buf[15]; int old_base; int new_base; if (argc < 2) { Message("Usage: RenumberBlock oldnum newnum"); return 1; } old_base = atoi (argv[0]); new_base = atoi (argv[1]); SET_FLAG (NAMEONPCBFLAG, PCB); ELEMENT_LOOP (PCB->Data); { char *refdes_split; char *cp; char *old_ref; char *new_ref; int num; if (!TEST_FLAG (SELECTEDFLAG, element) || EMPTY_STRING_P(element->Name[1].TextString)) continue; old_ref = element->Name[1].TextString; for (refdes_split = cp = old_ref; *cp; cp++) if (!isdigit (*cp)) refdes_split = cp+1; num = atoi (refdes_split); num += (new_base - old_base); sprintf(num_buf, "%d" ,num); new_ref = (char *) malloc (refdes_split - old_ref + strlen (num_buf) + 1); memcpy (new_ref, old_ref, refdes_split - old_ref); strcpy (new_ref + (refdes_split - old_ref), num_buf); AddObjectToChangeNameUndoList (ELEMENT_TYPE, NULL, NULL, element, NAMEONPCB_NAME (element)); ChangeObjectName (ELEMENT_TYPE, element, NULL, NULL, new_ref); } END_LOOP; IncrementUndoSerialNumber (); return 0; } /* %start-doc actions RenumberBuffer The @code{RenumberBuffer()} action renumbers all selected refdesses in the paste buffer. Usage: RenumberBuffer(oldnum,newnum) All selected elements are renumbered by adding (newnum-oldnum) to the existing number. To invoke it, use the command window, usually by typing ":". Example: @code{RenumberBuffer(0,10)} will change R2 to R12. %end-doc */ static int renumber_buffer (int argc, char **argv, Coord x, Coord y) { char num_buf[15]; int old_base; int new_base; if (argc < 2) { Message("Usage: RenumberBuffer oldnum newnum"); return 1; } old_base = atoi (argv[0]); new_base = atoi (argv[1]); SET_FLAG (NAMEONPCBFLAG, PCB); ELEMENT_LOOP (PASTEBUFFER->Data); { char *refdes_split; char *cp; char *old_ref; char *new_ref; int num; if (EMPTY_STRING_P(element->Name[1].TextString)) continue; old_ref = element->Name[1].TextString; for (refdes_split=cp=old_ref; *cp; cp++) if (!isdigit(*cp)) refdes_split = cp+1; num = atoi (refdes_split); num += (new_base - old_base); sprintf (num_buf, "%d" ,num); new_ref = (char *) malloc (refdes_split - old_ref + strlen (num_buf) + 1); memcpy (new_ref, old_ref, refdes_split - old_ref); strcpy (new_ref + (refdes_split - old_ref), num_buf); ChangeObjectName (ELEMENT_TYPE, element, NULL, NULL, new_ref); } END_LOOP; return 0; } static HID_Action renumber_block_action_list[] = { {"RenumberBlock", NULL, renumber_block, NULL, NULL}, {"RenumberBuffer", NULL, renumber_buffer, NULL, NULL} }; REGISTER_ACTIONS (renumber_block_action_list) void hid_renumber_init() { register_renumber_block_action_list(); } pcb-4.2.2/src/res_parse.c0000664000076400007640000013163213533277775012165 00000000000000 /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton implementation for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* Substitute the variable and function names. */ #define yyparse resparse #define yylex reslex #define yyerror reserror #define yylval reslval #define yychar reschar #define yydebug resdebug #define yynerrs resnerrs /* Copy the first part of user declarations. */ /* Line 189 of yacc.c */ #line 1 "res_parse.y" #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STRING_H #include #endif #define YYDEBUG 0 #define YYERROR_VERBOSE 1 /* #define YYSTYPE void * */ #include "global.h" #include "resource.h" #include "res_parse.h" #ifdef HAVE_LIBDMALLOC #include #endif static Resource *parsed_res; static Resource *current_res; int reserror(const char *); int reslex(); #define f(x) current_res->flags |= x /* Line 189 of yacc.c */ #line 118 "res_parse.c" /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { STRING = 258, INCLUDE = 259 }; #endif /* Tokens. */ #define STRING 258 #define INCLUDE 259 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 214 of yacc.c */ #line 40 "res_parse.y" int ival; char *sval; Resource *rval; /* Line 214 of yacc.c */ #line 170 "res_parse.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif /* Copy the second part of user declarations. */ /* Line 264 of yacc.c */ #line 182 "res_parse.c" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 3 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 25 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 8 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 7 /* YYNRULES -- Number of rules. */ #define YYNRULES 13 /* YYNRULES -- Number of states. */ #define YYNSTATES 18 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 259 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint8 yyprhs[] = { 0, 0, 3, 4, 7, 8, 13, 16, 17, 19, 23, 25, 27, 31 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int8 yyrhs[] = { 9, 0, -1, -1, 10, 13, -1, -1, 12, 5, 13, 6, -1, 14, 13, -1, -1, 3, -1, 3, 7, 3, -1, 4, -1, 11, -1, 3, 7, 11, -1, 1, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { 0, 52, 52, 52, 57, 57, 62, 62, 64, 65, 66, 67, 68, 69 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "STRING", "INCLUDE", "'{'", "'}'", "'='", "$accept", "top_res", "$@1", "res", "$@2", "res_item_zm", "res_item", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 123, 125, 61 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 8, 10, 9, 12, 11, 13, 13, 14, 14, 14, 14, 14, 14 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 0, 2, 0, 4, 2, 0, 1, 3, 1, 1, 3, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 2, 0, 0, 1, 13, 8, 10, 11, 0, 3, 0, 4, 0, 6, 9, 12, 0, 5 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { -1, 1, 2, 7, 8, 9, 10 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -1 static const yytype_int8 yypact[] = { -1, 2, 7, -1, -1, 13, -1, -1, 4, -1, 0, 11, 12, -1, -1, -1, 16, -1 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -1, -1, -1, 14, -1, 9, -1 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -8 static const yytype_int8 yytable[] = { -7, 4, 3, 5, 6, -4, -7, -7, 4, 12, 5, 6, -4, 4, 14, 5, 6, -4, -7, 13, 11, 16, 17, 0, 0, 15 }; static const yytype_int8 yycheck[] = { 0, 1, 0, 3, 4, 5, 6, 0, 1, 5, 3, 4, 5, 1, 3, 3, 4, 5, 6, 10, 7, 12, 6, -1, -1, 11 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 9, 10, 0, 1, 3, 4, 11, 12, 13, 14, 7, 5, 13, 3, 11, 13, 6 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ (Loc).last_line, (Loc).last_column) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into YYRESULT an error message about the unexpected token YYCHAR while in state YYSTATE. Return the number of bytes copied, including the terminating null byte. If YYRESULT is null, do not copy anything; just return the number of bytes that would be copied. As a special case, return 0 if an ordinary "syntax error" message will do. Return YYSIZE_MAXIMUM if overflow occurs during size calculation. */ static YYSIZE_T yysyntax_error (char *yyresult, int yystate, int yychar) { int yyn = yypact[yystate]; if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) return 0; else { int yytype = YYTRANSLATE (yychar); YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; int yysize_overflow = 0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; int yyx; # if 0 /* This is so xgettext sees the translatable formats that are constructed on the fly. */ YY_("syntax error, unexpected %s"); YY_("syntax error, unexpected %s, expecting %s"); YY_("syntax error, unexpected %s, expecting %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); # endif char *yyfmt; char const *yyf; static char const yyunexpected[] = "syntax error, unexpected %s"; static char const yyexpecting[] = ", expecting %s"; static char const yyor[] = " or %s"; char yyformat[sizeof yyunexpected + sizeof yyexpecting - 1 + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) * (sizeof yyor - 1))]; char const *yyprefix = yyexpecting; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 1; yyarg[0] = yytname[yytype]; yyfmt = yystpcpy (yyformat, yyunexpected); for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; yyformat[sizeof yyunexpected - 1] = '\0'; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; yyfmt = yystpcpy (yyfmt, yyprefix); yyprefix = yyor; } yyf = YY_(yyformat); yysize1 = yysize + yystrlen (yyf); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; if (yysize_overflow) return YYSIZE_MAXIMUM; if (yyresult) { /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ char *yyp = yyresult; int yyi = 0; while ((*yyp = *yyf) != '\0') { if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyf += 2; } else { yyp++; yyf++; } } } return yysize; } } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*-------------------------. | yyparse or yypush_parse. | `-------------------------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yytoken = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* Line 1455 of yacc.c */ #line 52 "res_parse.y" { current_res = parsed_res = resource_create(NULL); } break; case 4: /* Line 1455 of yacc.c */ #line 57 "res_parse.y" { current_res = resource_create(current_res); } break; case 5: /* Line 1455 of yacc.c */ #line 59 "res_parse.y" { (yyval.rval) = current_res; current_res = current_res->parent; } break; case 8: /* Line 1455 of yacc.c */ #line 64 "res_parse.y" { resource_add_val(current_res, 0, (yyvsp[(1) - (1)].sval), 0); f(FLAG_V); } break; case 9: /* Line 1455 of yacc.c */ #line 65 "res_parse.y" { resource_add_val(current_res, (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval), 0); f(FLAG_NV); } break; case 10: /* Line 1455 of yacc.c */ #line 66 "res_parse.y" { resource_add_val(current_res, 0, (yyvsp[(1) - (1)].sval), 0); f(FLAG_S); } break; case 11: /* Line 1455 of yacc.c */ #line 67 "res_parse.y" { resource_add_val(current_res, 0, 0, (yyvsp[(1) - (1)].rval)); f(FLAG_S); } break; case 12: /* Line 1455 of yacc.c */ #line 68 "res_parse.y" { resource_add_val(current_res, (yyvsp[(1) - (3)].sval), 0, (yyvsp[(3) - (3)].rval)); f(FLAG_NS); } break; /* Line 1455 of yacc.c */ #line 1429 "res_parse.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) { YYSIZE_T yyalloc = 2 * yysize; if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) yyalloc = YYSTACK_ALLOC_MAXIMUM; if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yyalloc); if (yymsg) yymsg_alloc = yyalloc; else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; } } if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); yyerror (yymsg); } else { yyerror (YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } } #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } *++yyvsp = yylval; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } /* Line 1675 of yacc.c */ #line 72 "res_parse.y" static const char *res_filename = NULL; static FILE *res_file = NULL; static const char **res_strings = NULL; static int res_string_idx = 0; int res_lineno; int res_parse_getchars(char *buf, int max_size) { if (res_file) { int i = fgetc(res_file); buf[0] = i; if (i == EOF) return 0; } else { if (res_strings[0] == 0) return 0; buf[0] = res_strings[0][res_string_idx]; res_string_idx ++; if (buf[0] == 0) { res_strings ++; res_string_idx = 0; buf[0] = '\n'; return 1; } } return 1; } Resource * resource_parse(const char *filename, const char **strings) { res_lineno = 1; if (filename) { res_file = fopen (filename, "r"); if (res_file == NULL) { perror(filename); return NULL; } res_filename = filename; } else if (strings) { res_strings = strings; res_string_idx = 0; } else return NULL; #if YYDEBUG yydebug = 1; #endif if (resparse()) parsed_res = NULL; if (filename) { fclose (res_file); res_filename = NULL; res_file = NULL; } else res_strings = NULL; return parsed_res; } Resource * resource_create(Resource *parent) { Resource *rv = (Resource *)malloc(sizeof(Resource)); rv->parent = parent; rv->flags = 0; rv->c = 0; rv->v = (ResourceVal *)malloc(sizeof(ResourceVal)); return rv; } void resource_add_val(Resource *n, char *name, char *value, Resource *subres) { n->v = (ResourceVal *)realloc(n->v, sizeof(ResourceVal)*(n->c+1)); n->v[n->c].name = name; n->v[n->c].value = value; n->v[n->c].subres = subres; n->c++; } char * resource_value(const Resource *res, char *name) { int i; if (res == 0 || name == 0) return 0; for (i=0; ic; i++) if (res->v[i].name && res->v[i].value && NSTRCMP(res->v[i].name, name) == 0) return res->v[i].value; return 0; } Resource * resource_subres(const Resource *res, const char *name) { int i; if (res == 0 || name == 0) return 0; for (i=0; ic; i++) if (res->v[i].name && res->v[i].subres && NSTRCMP(res->v[i].name, name) == 0) return res->v[i].subres; return 0; } int reserror(const char *str) { fprintf(stderr, "Error: %s around line %d: %s\n", res_file ? res_filename : "internal strings", res_lineno, str); return 0; } static void dump_res(Resource *n, int l) { int i; for (i=0; ic; i++) { if (n->v[i].subres) { printf("%*cn[%s] = {\n", l, ' ', n->v[i].name? n->v[i].name :""); dump_res(n->v[i].subres, l+3); printf("%*c}\n", l, ' '); } else printf("%*cn[%s] = v[%s]\n", l, ' ', n->v[i].name? n->v[i].name :"", n->v[i].value? n->v[i].value :""); } } void resource_dump (Resource *r) { dump_res (r, 0); } pcb-4.2.2/src/flags.h0000664000076400007640000000603113533277055011264 00000000000000/*! * \file src/flags.h * * \brief Some commonly used macros not related to a special C-file. * * The file is included by global.h after const.h * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_FLAGS_H #define PCB_FLAGS_H #include #include "globalconst.h" /*! * \brief Nobody should know about the internals of this except the * macros below that access it. * * This structure must be simple-assignable for now. */ typedef struct { unsigned long f; /* generic flags */ unsigned char t[(MAX_LAYER + 1) / 2]; /* thermals */ } FlagType; int pcb_flag_eq (FlagType *f1, FlagType *f2); /* --------------------------------------------------------------------------- * some routines for flag setting, clearing, changing and testing */ #define SET_FLAG(F,P) ((P)->Flags.f |= (F)) #define CLEAR_FLAG(F,P) ((P)->Flags.f &= (~(F))) #define TEST_FLAG(F,P) ((P)->Flags.f & (F) ? 1 : 0) #define TOGGLE_FLAG(F,P) ((P)->Flags.f ^= (F)) #define ASSIGN_FLAG(F,V,P) ((P)->Flags.f = ((P)->Flags.f & (~(F))) | ((V) ? (F) : 0)) #define TEST_FLAGS(F,P) (((P)->Flags.f & (F)) == (F) ? 1 : 0) #define FLAGS_EQUAL(F1,F2) pcb_flag_eq(&(F1), &(F2)) #define THERMFLAG(L) (0xf << (4 *((L) % 2))) #define TEST_THERM(L,P) ((P)->Flags.t[(L)/2] & THERMFLAG(L) ? 1 : 0) #define GET_THERM(L,P) (((P)->Flags.t[(L)/2] >> (4 * ((L) % 2))) & 0xf) #define CLEAR_THERM(L,P) (P)->Flags.t[(L)/2] &= ~THERMFLAG(L) #define ASSIGN_THERM(L,V,P) (P)->Flags.t[(L)/2] = ((P)->Flags.t[(L)/2] & ~THERMFLAG(L)) | ((V) << (4 * ((L) % 2))) //defined in misc.c extern int mem_any_set (unsigned char *, int); #define TEST_ANY_THERMS(P) mem_any_set((P)->Flags.t, sizeof((P)->Flags.t)) /* For passing modified flags to other functions. */ FlagType MakeFlags (unsigned int); FlagType OldFlags (unsigned int); FlagType AddFlags (FlagType, unsigned int); FlagType MaskFlags (FlagType, unsigned int); #define NoFlags() MakeFlags(0) bool ClearFlagOnLinesAndPolygons (int flag, bool undoable); bool ClearFlagOnPinsViasAndPads (int flag, bool undoable); bool ClearFlagOnAllObjects (int flag, bool undoable); #endif // ifndef PCB_FLAGS_H pcb-4.2.2/src/parse_l.l0000664000076400007640000002146013434555140011616 00000000000000%{ /* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996,2006 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * */ /* lexical definitions to parse ASCII input of PCB and Element description */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #if defined(_POSIX_SOURCE) || defined(_HPUX_SOURCE) #include #endif #include "global.h" #ifdef HAVE_LIBDMALLOC # include /* see http://dmalloc.com */ #endif #include "global.h" #include "crosshair.h" #include "data.h" #include "error.h" #include "file.h" #include "mymem.h" #include "misc.h" #include "strflags.h" #include "parse_l.h" #include "parse_y.h" #include "create.h" #define YY_NO_INPUT /* --------------------------------------------------------------------------- * some shared parser identifiers */ #ifdef FLEX_SCANNER #define yyunput ATTRIBUTE_UNUSED yyunput #endif char *yyfilename; /* in this file */ PCBType *yyPCB; /* used by parser */ DataType *yyData; ElementType *yyElement; FontType *yyFont; static int parse_number (void); /* --------------------------------------------------------------------------- * an external prototypes */ int yyparse(void); /* --------------------------------------------------------------------------- * some local prototypes */ static int Parse(char *, char *, char *, char *); %} HEX 0x[0-9a-fA-F]+ INTEGER [+-]?([1-9][0-9]*|0) FLOATING {INTEGER}?"."[0-9]* STRINGCHAR ([^"\n\r\\]|\\.) %option yylineno %% FileVersion { return(T_FILEVERSION); } PCB { return(T_PCB); } Grid { return(T_GRID); } Cursor { return(T_CURSOR); } Thermal { return(T_THERMAL); } PolyArea { return(T_AREA); } DRC { return(T_DRC); } Flags { return(T_FLAGS); } Layer { return(T_LAYER); } Pin { return(T_PIN); } Pad { return(T_PAD); } Via { return(T_VIA); } Line { return(T_LINE); } Rat { return(T_RAT); } Rectangle { return(T_RECTANGLE); } Text { return(T_TEXT); } ElementLine { return(T_ELEMENTLINE); } ElementArc { return(T_ELEMENTARC); } Element { return(T_ELEMENT); } SymbolLine { return(T_SYMBOLLINE); } Symbol { return(T_SYMBOL); } Mark { return(T_MARK); } Groups { return(T_GROUPS); } Styles { return(T_STYLES); } Polygon { return(T_POLYGON); } Hole { return(T_POLYGON_HOLE); } Arc { return(T_ARC); } NetList { return(T_NETLIST); } Net { return(T_NET); } Connect { return(T_CONN); } Attribute { return(T_ATTRIBUTE); } nm { return T_NM; } um { return T_UM; } mm { return T_MM; } m { return T_M; } km { return T_KM; } umil { return T_UMIL; } cmil { return T_CMIL; } mil { return T_MIL; } in { return T_IN; } px { return T_PX; } \'.\' { yylval.integer = (unsigned) *(yytext+1); return(CHAR_CONST); } {FLOATING} { return parse_number(); } {INTEGER} { yylval.integer = round (g_ascii_strtod (yytext, NULL)); return INTEGER; } {HEX} { unsigned n; sscanf((char *) yytext, "%x", &n); yylval.integer = n; return INTEGER; } \"{STRINGCHAR}*\" { char *p1, *p2; /* return NULL on empty string */ if (yyleng == 2) { yylval.string = NULL; return(STRING); } /* allocate memory and copy string; * stringlength is counted and copied without * leading and trailing '"' */ yyleng -= 2; yylval.string = (char *)calloc (yyleng+1, sizeof (char)); p1 = (char *) (yytext +1); p2 = yylval.string; while(yyleng--) { /* check for special character */ if (*p1 == '\\') { yyleng--; p1++; } *p2++ = *p1++; } *p2 = '\0'; return(STRING); } #.* {} [ \t]+ {} [\n] { #ifndef FLEX_SCANNER yylineno++; #endif } [\r] {} . { return(*yytext); } %% /* --------------------------------------------------------------------------- * sets up the preprocessor command */ static int Parse(char *Executable, char *Path, char *Filename, char *Parameter) { static char *command = NULL; int returncode; int used_popen = 0; char *tmps; size_t l; #ifdef FLEX_SCANNER static bool firsttime = true; #endif if (EMPTY_STRING_P (Executable)) { l = 2; if ( Path != NULL ) l += strlen (Path); l += strlen (Filename); if ( (tmps = (char *) malloc ( l * sizeof (char))) == NULL) { fprintf (stderr, "Parse(): malloc failed\n"); exit (1); } if ( Path != NULL && *Path != '\0') sprintf (tmps, "%s%s%s", Path, PCB_DIR_SEPARATOR_S, Filename); else sprintf (tmps, "%s", Filename); yyin = fopen (tmps, "r"); if (!yyin) { /* Special case this one, we get it all the time... */ if (strcmp (tmps, "./default_font")) Message("Can't open %s for reading\n", tmps); return(1); } free (tmps); } else { used_popen = 1; /* release old command and create new from template */ free (command); command = EvaluateFilename(Executable, Path, Filename, Parameter); /* open pipe to stdout of command */ if (*command == '\0' || (yyin = popen(command, "r")) == NULL) { PopenErrorMessage(command); return(1); } } #ifdef FLEX_SCANNER /* reset parser if not called the first time */ if (!firsttime) yyrestart(yyin); firsttime = false; #endif /* init linenumber and filename for yyerror() */ yylineno = 1; yyfilename = Filename; /* We need to save the data temporarily because lex-yacc are able * to break the application if the input file has an illegal format. * It's not necessary if the system supports the call of functions * on termination. */ CreateBeLenient (true); #if !defined(HAS_ATEXIT) && !defined(HAS_ON_EXIT) if (PCB && PCB->Data) SaveTMPData(); returncode = yyparse(); RemoveTMPData(); #else returncode = yyparse(); #endif /* clean up parse buffer */ yy_delete_buffer(YY_CURRENT_BUFFER); CreateBeLenient (false); if (used_popen) return(pclose(yyin) ? 1 : returncode); return(fclose(yyin) ? 1 : returncode); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a single element file */ int ParseElementFile (DataType *Ptr, char *Filename) { yyPCB = NULL; yyData = Ptr; yyFont = &PCB->Font; yyElement = NULL; return(Parse(NULL,NULL,Filename,NULL)); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a single library entry */ int ParseLibraryEntry (DataType *Ptr, char *Template) { yyPCB = NULL; yyData = Ptr; yyFont = &PCB->Font; yyElement = NULL; return(Parse(Settings.LibraryCommand, Settings.LibraryPath, Settings.LibraryFilename, Template)); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a complete board */ int ParsePCB (PCBType *Ptr, char *Filename) { yyPCB = Ptr; yyData = NULL; yyFont = NULL; yyElement = NULL; return(Parse(Settings.FileCommand, Settings.FilePath, Filename, NULL)); } /* --------------------------------------------------------------------------- * initializes LEX and calls parser for a font */ int ParseFont (FontType *Ptr, char *Filename) { int r = 0; char *path, *p; yyPCB = NULL; yyFont = Ptr; yyElement = NULL; path = strdup (Settings.FontPath); /* search through the font path for a font file */ for (p = strtok (path, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER)) { #ifdef DEBUG Message ("Looking for %s in %s\n", Filename, p); #endif r = Parse(Settings.FontCommand, p, Filename, NULL); if (r == 0) { #ifdef DEBUG Message ("Found %s in %s\n", Filename, p); #endif break; } } free (path); return r; } static int parse_number () { yylval.number = g_ascii_strtod ((gchar *) yytext, NULL); return FLOATING; } pcb-4.2.2/src/rtree.h0000664000076400007640000000451013434555140011303 00000000000000/*! * \file src/rtree.h * * \brief Prototypes for r-tree routines. * * \author This file, rtree.h, was written and is Copyright (c) 2004 * harry eaton, it's based on C. Scott's kdtree.h template. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * * haceaton@aplcomm.jhuapl.edu */ #ifndef PCB_RTREE_H #define PCB_RTREE_H #include "global.h" rtree_t *r_create_tree (const BoxType * boxlist[], int N, int manage); void r_destroy_tree (rtree_t ** rtree); bool r_delete_entry (rtree_t * rtree, const BoxType * which); void r_insert_entry (rtree_t * rtree, const BoxType * which, int manage); int r_search (rtree_t * rtree, const BoxType * starting_region, int (*region_in_search) (const BoxType * region, void *cl), int (*rectangle_in_region) (const BoxType * box, void *cl), void *closure); static inline int r_search_pt (rtree_t * rtree, const PointType * pt, int radius, int (*region_in_search) (const BoxType * region, void *cl), int (*rectangle_in_region) (const BoxType * box, void *cl), void *closure) { BoxType box; box.X1 = pt->X - radius; box.X2 = pt->X + radius; box.Y1 = pt->Y - radius; box.Y2 = pt->Y + radius; return r_search(rtree, &box, region_in_search, rectangle_in_region, closure); } int r_region_is_empty (rtree_t * rtree, const BoxType * region); void __r_dump_tree (struct rtree_node *, int); #endif pcb-4.2.2/src/mirror.c0000664000076400007640000000653313434555140011476 00000000000000/*! * \file src/mirror.c * * \brief Functions used to change the mirror flag of an object. * * An undo operation is not implemented because it's easy to * recover an object. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "global.h" #include "data.h" #include "draw.h" #include "mirror.h" #include "misc.h" #include "polygon.h" #include "search.h" #include "select.h" #include "set.h" #ifdef HAVE_LIBDMALLOC #include #endif /*! * \brief Mirrors the coordinates of an element. * * An additional offset is passed. */ void MirrorElementCoordinates (DataType *Data, ElementType *Element, Coord yoff) { r_delete_element (Data, Element); ELEMENTLINE_LOOP (Element); { line->Point1.X = SWAP_X (line->Point1.X); line->Point1.Y = SWAP_Y (line->Point1.Y) + yoff; line->Point2.X = SWAP_X (line->Point2.X); line->Point2.Y = SWAP_Y (line->Point2.Y) + yoff; } END_LOOP; PIN_LOOP (Element); { RestoreToPolygon (Data, PIN_TYPE, Element, pin); pin->X = SWAP_X (pin->X); pin->Y = SWAP_Y (pin->Y) + yoff; } END_LOOP; PAD_LOOP (Element); { Coord X1,X2,Y1,Y2; RestoreToPolygon (Data, PAD_TYPE, Element, pad); X1 = SWAP_X (pad->Point1.X); Y1 = SWAP_Y (pad->Point1.Y) + yoff; X2 = SWAP_X (pad->Point2.X); Y2 = SWAP_Y (pad->Point2.Y) + yoff; /* copy values */ if (X1 > X2 || (X1 == X2 && Y1 > Y2)) { pad->Point1.X = X2; pad->Point1.Y = Y2; pad->Point2.X = X1; pad->Point2.Y = Y1; } else { pad->Point1.X = X1; pad->Point1.Y = Y1; pad->Point2.X = X2; pad->Point2.Y = Y2; } TOGGLE_FLAG (ONSOLDERFLAG, pad); } END_LOOP; ARC_LOOP (Element); { arc->X = SWAP_X (arc->X); arc->Y = SWAP_Y (arc->Y) + yoff; arc->StartAngle = SWAP_ANGLE (arc->StartAngle); arc->Delta = SWAP_DELTA (arc->Delta); } END_LOOP; ELEMENTTEXT_LOOP (Element); { text->X = SWAP_X (text->X); text->Y = SWAP_Y (text->Y) + yoff; TOGGLE_FLAG (ONSOLDERFLAG, text); } END_LOOP; Element->MarkX = SWAP_X (Element->MarkX); Element->MarkY = SWAP_Y (Element->MarkY) + yoff; /* now toggle the solder-side flag */ TOGGLE_FLAG (ONSOLDERFLAG, Element); /* this inserts all of the rtree data too */ SetElementBoundingBox (Data, Element, &PCB->Font); ClearFromPolygon (Data, ELEMENT_TYPE, Element, Element); } pcb-4.2.2/src/intersect.c0000664000076400007640000002112413434555140012155 00000000000000/*! * \file src/intersect.c * * \brief Rectangle intersection/union routines. * * \author this file, intersect.c, was written and is * Copyright (c) 2001 C. Scott Ananian. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include #include "data.h" #include "intersect.h" #include "mymem.h" #ifdef HAVE_LIBDMALLOC #include #endif /* --------------------------------------------------------------------------- * some local prototypes */ static int compareleft (const void *ptr1, const void *ptr2); static int compareright (const void *ptr1, const void *ptr2); static int comparepos (const void *ptr1, const void *ptr2); static int nextpwrof2 (int i); /* --------------------------------------------------------------------------- * some local types */ typedef struct { Coord left, right; int covered; Coord area; } SegmentTreeNode; typedef struct { SegmentTreeNode *nodes; int size; } SegmentTree; typedef struct { Coord *p; int size; } LocationList; /*! * \brief Create a sorted list of unique y coords from a BoxList. */ static LocationList createSortedYList (BoxListType *boxlist) { LocationList yCoords; Coord last; int i, n; /* create sorted list of Y coordinates */ yCoords.size = 2 * boxlist->BoxN; yCoords.p = (Coord *)calloc (yCoords.size, sizeof (*yCoords.p)); for (i = 0; i < boxlist->BoxN; i++) { yCoords.p[2 * i] = boxlist->Box[i].Y1; yCoords.p[2 * i + 1] = boxlist->Box[i].Y2; } qsort (yCoords.p, yCoords.size, sizeof (*yCoords.p), comparepos); /* count uniq y coords */ last = 0; for (n = 0, i = 0; i < yCoords.size; i++) if (i == 0 || yCoords.p[i] != last) yCoords.p[n++] = last = yCoords.p[i]; yCoords.size = n; return yCoords; } /*! * \brief Create an empty segment tree from the given sorted list of * unique y coords. */ static SegmentTree createSegmentTree (Coord * yCoords, int N) { SegmentTree st; int i; /* size is twice the nearest larger power of 2 */ st.size = 2 * nextpwrof2 (N); st.nodes = (SegmentTreeNode *)calloc (st.size, sizeof (*st.nodes)); /* initialize the rightmost leaf node */ st.nodes[st.size - 1].left = (N > 0) ? yCoords[--N] : 10; st.nodes[st.size - 1].right = st.nodes[st.size - 1].left + 1; /* initialize the rest of the leaf nodes */ for (i = st.size - 2; i >= st.size / 2; i--) { st.nodes[i].right = st.nodes[i + 1].left; st.nodes[i].left = (N > 0) ? yCoords[--N] : st.nodes[i].right - 1; } /* initialize the internal nodes */ for (; i > 0; i--) { /* node 0 is not used */ st.nodes[i].right = st.nodes[2 * i + 1].right; st.nodes[i].left = st.nodes[2 * i].left; } /* done! */ return st; } void insertSegment (SegmentTree * st, int n, Coord Y1, Coord Y2) { Coord discriminant; if (st->nodes[n].left >= Y1 && st->nodes[n].right <= Y2) { st->nodes[n].covered++; } else { assert (n < st->size / 2); discriminant = st->nodes[n * 2 + 1 /*right */ ].left; if (Y1 < discriminant) insertSegment (st, n * 2, Y1, Y2); if (discriminant < Y2) insertSegment (st, n * 2 + 1, Y1, Y2); } /* fixup area */ st->nodes[n].area = (st->nodes[n].covered > 0) ? (st->nodes[n].right - st->nodes[n].left) : (n >= st->size / 2) ? 0 : st->nodes[n * 2].area + st->nodes[n * 2 + 1].area; } void deleteSegment (SegmentTree * st, int n, Coord Y1, Coord Y2) { Coord discriminant; if (st->nodes[n].left >= Y1 && st->nodes[n].right <= Y2) { assert (st->nodes[n].covered); --st->nodes[n].covered; } else { assert (n < st->size / 2); discriminant = st->nodes[n * 2 + 1 /*right */ ].left; if (Y1 < discriminant) deleteSegment (st, n * 2, Y1, Y2); if (discriminant < Y2) deleteSegment (st, n * 2 + 1, Y1, Y2); } /* fixup area */ st->nodes[n].area = (st->nodes[n].covered > 0) ? (st->nodes[n].right - st->nodes[n].left) : (n >= st->size / 2) ? 0 : st->nodes[n * 2].area + st->nodes[n * 2 + 1].area; } /*! * \brief Compute the area of the intersection of the given rectangles. * * That is the area covered by more than one rectangle (counted twice if * the area is covered by three rectangles, three times if covered by * four rectangles, etc.). * * \note Runs in O(N ln N) time. */ double ComputeIntersectionArea (BoxListType *boxlist) { Cardinal i; double area = 0.0; /* first get the aggregate area. */ for (i = 0; i < boxlist->BoxN; i++) area += (double) (boxlist->Box[i].X2 - boxlist->Box[i].X1) * (double) (boxlist->Box[i].Y2 - boxlist->Box[i].Y1); /* intersection area is aggregate - union. */ return area * 0.0001 - ComputeUnionArea (boxlist); } /*! * \brief Compute the area of the union of the given rectangles. * * \note Runs in O(N ln N) time. */ double ComputeUnionArea (BoxListType *boxlist) { BoxType **rectLeft, **rectRight; Cardinal i, j; LocationList yCoords; SegmentTree segtree; Coord lastX; double area = 0.0; if (boxlist->BoxN == 0) return 0.0; /* create sorted list of Y coordinates */ yCoords = createSortedYList (boxlist); /* now create empty segment tree */ segtree = createSegmentTree (yCoords.p, yCoords.size); free (yCoords.p); /* create sorted list of left and right X coordinates of rectangles */ rectLeft = (BoxType **)calloc (boxlist->BoxN, sizeof (*rectLeft)); rectRight = (BoxType **)calloc (boxlist->BoxN, sizeof (*rectRight)); for (i = 0; i < boxlist->BoxN; i++) { assert (boxlist->Box[i].X1 <= boxlist->Box[i].X2); assert (boxlist->Box[i].Y1 <= boxlist->Box[i].Y2); rectLeft[i] = rectRight[i] = &boxlist->Box[i]; } qsort (rectLeft, boxlist->BoxN, sizeof (*rectLeft), compareleft); qsort (rectRight, boxlist->BoxN, sizeof (*rectRight), compareright); /* sweep through x segments from left to right */ i = j = 0; lastX = rectLeft[0]->X1; while (j < boxlist->BoxN) { assert (i <= boxlist->BoxN); /* i will step through rectLeft, j will through rectRight */ if (i == boxlist->BoxN || rectRight[j]->X2 < rectLeft[i]->X1) { /* right edge of rectangle */ BoxType *b = rectRight[j++]; /* check lastX */ if (b->X2 != lastX) { assert (lastX < b->X2); area += (double) (b->X2 - lastX) * segtree.nodes[1].area; lastX = b->X2; } /* remove a segment from the segment tree. */ deleteSegment (&segtree, 1, b->Y1, b->Y2); } else { /* left edge of rectangle */ BoxType *b = rectLeft[i++]; /* check lastX */ if (b->X1 != lastX) { assert (lastX < b->X1); area += (double) (b->X1 - lastX) * segtree.nodes[1].area; lastX = b->X1; } /* add a segment from the segment tree. */ insertSegment (&segtree, 1, b->Y1, b->Y2); } } free (rectLeft); free (rectRight); free (segtree.nodes); return area * 0.0001; } static int compareleft (const void *ptr1, const void *ptr2) { BoxType **b1 = (BoxType **) ptr1; BoxType **b2 = (BoxType **) ptr2; return (*b1)->X1 - (*b2)->X1; } static int compareright (const void *ptr1, const void *ptr2) { BoxType **b1 = (BoxType **) ptr1; BoxType **b2 = (BoxType **) ptr2; return (*b1)->X2 - (*b2)->X2; } static int comparepos (const void *ptr1, const void *ptr2) { return *((Coord *) ptr1) - *((Coord *) ptr2); } static int nextpwrof2 (int n) { int r = 1; while (n != 0) { n /= 2; r *= 2; } return r; } pcb-4.2.2/src/dolists.h0000664000076400007640000000054212747101744011647 00000000000000#undef REGISTER_ACTIONS #undef REGISTER_ATTRIBUTES #undef REGISTER_FLAGS #define REGISTER_ACTIONS(a) {extern void HIDCONCAT(register_,a)();HIDCONCAT(register_,a)();} #define REGISTER_ATTRIBUTES(a) {extern void HIDCONCAT(register_,a)();HIDCONCAT(register_,a)();} #define REGISTER_FLAGS(a) {extern void HIDCONCAT(register_,a)();HIDCONCAT(register_,a)();} pcb-4.2.2/src/vendor.h0000664000076400007640000000202413533277055011463 00000000000000/*! * \file src/vendor.h * * \brief . * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2004 Dan McMahill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PCB_VENDOR_H #define PCB_VENDOR_H int vendorDrillMap (int); bool vendorIsElementMappable (ElementType *); #endif /* PCB_VENDOR_H */ pcb-4.2.2/src/vector.h0000664000076400007640000000466013434555140011472 00000000000000/*! * \file src/vector.h * * \brief Prototypes for vectors routines. * * \author this file, vector.c, was written and is * Copyright (c) 2001 C. Scott Ananian. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * * haceaton@aplcomm.jhuapl.edu */ #ifndef PCB_VECTOR_H #define PCB_VECTOR_H /*! * \brief What a vector looks like. */ typedef struct vector_struct vector_t; /*! * \brief What data in a vector looks like. */ typedef void *vector_element_t; vector_t *vector_create (); void vector_destroy (vector_t ** vector); vector_t *vector_duplicate (vector_t * vector); /* -- interrogation -- */ int vector_is_empty (vector_t * vector); int vector_size (vector_t * vector); vector_element_t vector_element (vector_t * vector, int N); vector_element_t vector_element_first (vector_t * vector); vector_element_t vector_element_last (vector_t * vector); /* -- mutation -- */ void vector_append (vector_t * vector, vector_element_t data); void vector_append_many (vector_t * vector, vector_element_t data[], int count); void vector_append_vector (vector_t * vector, vector_t * other_vector); void vector_insert (vector_t * vector, int N, vector_element_t data); void vector_insert_many (vector_t * vector, int N, vector_element_t data[], int count); vector_element_t vector_remove_last (vector_t * vector); vector_element_t vector_remove (vector_t * vector, int N); vector_element_t vector_replace (vector_t * vector, vector_element_t data, int N); #endif /* PCB_VECTOR_H */ pcb-4.2.2/src/drill.c0000664000076400007640000001722113434555140011266 00000000000000/*! * \file src/drill.c * * \brief . * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This module, drill.c, was written and is Copyright (C) 1997 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "data.h" #include "error.h" #include "mymem.h" #ifdef HAVE_LIBDMALLOC #include #endif /* * some local prototypes */ static void FillDrill (DrillType *, ElementType *, PinType *); static void InitializeDrill (DrillType *, PinType *, ElementType *); static void FillDrill (DrillType *Drill, ElementType *Element, PinType *Pin) { Cardinal n; ElementType **ptr; PinType **pin; pin = GetDrillPinMemory (Drill); *pin = Pin; if (Element) { Drill->PinCount++; for (n = Drill->ElementN - 1; n != -1; n--) if (Drill->Element[n] == Element) break; if (n == -1) { ptr = GetDrillElementMemory (Drill); *ptr = Element; } } else Drill->ViaCount++; if (TEST_FLAG (HOLEFLAG, Pin)) Drill->UnplatedCount++; } static void InitializeDrill (DrillType *drill, PinType *pin, ElementType *element) { void *ptr; drill->DrillSize = pin->DrillingHole; drill->ElementN = 0; drill->ViaCount = 0; drill->PinCount = 0; drill->UnplatedCount = 0; drill->ElementMax = 0; drill->Element = NULL; drill->PinN = 0; drill->Pin = NULL; drill->PinMax = 0; ptr = (void *) GetDrillPinMemory (drill); *((PinType **) ptr) = pin; if (element) { ptr = (void *) GetDrillElementMemory (drill); *((ElementType **) ptr) = element; drill->PinCount = 1; } else drill->ViaCount = 1; if (TEST_FLAG (HOLEFLAG, pin)) drill->UnplatedCount = 1; } static int DrillQSort (const void *va, const void *vb) { DrillType *a = (DrillType *) va; DrillType *b = (DrillType *) vb; return a->DrillSize - b->DrillSize; } DrillInfoType * GetDrillInfo (DataType *top) { DrillInfoType *AllDrills; DrillType *Drill = NULL; DrillType savedrill, swapdrill; bool DrillFound = false; bool NewDrill; AllDrills = (DrillInfoType *)calloc (1, sizeof (DrillInfoType)); ALLPIN_LOOP (top); { if (!DrillFound) { DrillFound = true; Drill = GetDrillInfoDrillMemory (AllDrills); InitializeDrill (Drill, pin, element); } else { if (Drill->DrillSize == pin->DrillingHole) FillDrill (Drill, element, pin); else { NewDrill = false; DRILL_LOOP (AllDrills); { if (drill->DrillSize == pin->DrillingHole) { Drill = drill; FillDrill (Drill, element, pin); break; } else if (drill->DrillSize > pin->DrillingHole) { if (!NewDrill) { NewDrill = true; InitializeDrill (&swapdrill, pin, element); Drill = GetDrillInfoDrillMemory (AllDrills); Drill->DrillSize = pin->DrillingHole + 1; Drill = drill; } savedrill = *drill; *drill = swapdrill; swapdrill = savedrill; } } END_LOOP; if (AllDrills->Drill[AllDrills->DrillN - 1].DrillSize < pin->DrillingHole) { Drill = GetDrillInfoDrillMemory (AllDrills); InitializeDrill (Drill, pin, element); } } } } ENDALL_LOOP; VIA_LOOP (top); { if (!DrillFound) { DrillFound = true; Drill = GetDrillInfoDrillMemory (AllDrills); Drill->DrillSize = via->DrillingHole; FillDrill (Drill, NULL, via); } else { if (Drill->DrillSize != via->DrillingHole) { DRILL_LOOP (AllDrills); { if (drill->DrillSize == via->DrillingHole) { Drill = drill; FillDrill (Drill, NULL, via); break; } } END_LOOP; if (Drill->DrillSize != via->DrillingHole) { Drill = GetDrillInfoDrillMemory (AllDrills); Drill->DrillSize = via->DrillingHole; FillDrill (Drill, NULL, via); } } else FillDrill (Drill, NULL, via); } } END_LOOP; qsort (AllDrills->Drill, AllDrills->DrillN, sizeof (DrillType), DrillQSort); return (AllDrills); } #define ROUND(x,n) ((int)(((x)+(n)/2)/(n))*(n)) /* Currently unused. Was used in ReportDrills() in report.c and in PrintFab() in print.c (generation of the Gerber fab file), but not when generating the actual CNC files, so the number of drills in the drill report and in the CNC file could differ. This was confusing. */ #if 0 /*! \brief Join similar sized drill sets. \param d Set of all drills to look at, in subsets for each drill size. \param roundto Rounding error. Drills differing less than this value are considered to be of the pame size and joined into a common set. \note In case of hits the number of drill sets changes, so the number of distinct drill sizes changes as well. This can be confusing if RoundDisplayInfo() is used for one kind of display/output, but not for others. */ void RoundDrillInfo (DrillInfoType *d, int roundto) { unsigned int i = 0; /* round in the case with only one drill, too */ if (d->DrillN == 1) { d->Drill[0].DrillSize = ROUND (d->Drill[0].DrillSize, roundto); } while ((d->DrillN > 0) && (i < d->DrillN - 1)) { int diam1 = ROUND (d->Drill[i].DrillSize, roundto); int diam2 = ROUND (d->Drill[i + 1].DrillSize, roundto); if (diam1 == diam2) { int ei, ej; d->Drill[i].ElementMax = d->Drill[i].ElementN + d->Drill[i+1].ElementN; if (d->Drill[i].ElementMax) { d->Drill[i].Element = (ElementType **)realloc (d->Drill[i].Element, d->Drill[i].ElementMax * sizeof (ElementType *)); for (ei = 0; ei < d->Drill[i+1].ElementN; ei++) { for (ej = 0; ej < d->Drill[i].ElementN; ej++) if (d->Drill[i].Element[ej] == d->Drill[i + 1].Element[ei]) break; if (ej == d->Drill[i].ElementN) d->Drill[i].Element[d->Drill[i].ElementN++] = d->Drill[i + 1].Element[ei]; } } free (d->Drill[i + 1].Element); d->Drill[i + 1].Element = NULL; d->Drill[i].PinMax = d->Drill[i].PinN + d->Drill[i + 1].PinN; d->Drill[i].Pin = (PinType **)realloc (d->Drill[i].Pin, d->Drill[i].PinMax * sizeof (PinType *)); memcpy (d->Drill[i].Pin + d->Drill[i].PinN, d->Drill[i + 1].Pin, d->Drill[i + 1].PinN * sizeof (PinType *)); d->Drill[i].PinN += d->Drill[i + 1].PinN; free (d->Drill[i + 1].Pin); d->Drill[i + 1].Pin = NULL; d->Drill[i].PinCount += d->Drill[i + 1].PinCount; d->Drill[i].ViaCount += d->Drill[i + 1].ViaCount; d->Drill[i].UnplatedCount += d->Drill[i + 1].UnplatedCount; d->Drill[i].DrillSize = diam1; memmove (d->Drill + i + 1, d->Drill + i + 2, (d->DrillN - i - 2) * sizeof (DrillType)); d->DrillN--; } else { d->Drill[i].DrillSize = diam1; i++; } } } #endif void FreeDrillInfo (DrillInfoType *Drills) { DRILL_LOOP (Drills); { free (drill->Element); free (drill->Pin); } END_LOOP; free (Drills->Drill); free (Drills); } pcb-4.2.2/src/rats.c0000664000076400007640000006734513533277055011153 00000000000000/*! * \file src/rats.c * * \brief Rats nest routines. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1997, harry eaton * * This module, rats.c, was written and is Copyright (C) 1997 by * harry eaton. * * This module is also subject to the GNU GPL as described below. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Change History: * Started 6/10/97 * Added support for minimum length rat lines 6/13/97 * rat lines to nearest line/via 8/29/98 * support for netlist window 10/24/98 */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "global.h" #include "create.h" #include "data.h" #include "draw.h" #include "error.h" #include "file.h" #include "find.h" #include "flags.h" #include "misc.h" #include "mymem.h" #include "polygon.h" #include "rats.h" #include "search.h" #include "set.h" #include "undo.h" #ifdef HAVE_LIBDMALLOC #include #endif #define TRIEDFIRST 0x1 #define BESTFOUND 0x2 /* --------------------------------------------------------------------------- * some forward declarations */ static bool FindPad (char *, char *, ConnectionType *, bool); static bool ParseConnection (char *, char *, char *); static bool DrawShortestRats (NetListType *, void (*)(register ConnectionType *, register ConnectionType *, register RouteStyleType *)); static bool GatherSubnets (NetListType *, bool, bool); static bool CheckShorts (LibraryMenuType *); static void TransferNet (NetListType *, NetType *, NetType *); /* --------------------------------------------------------------------------- * some local identifiers */ static bool badnet = false; static Cardinal top_group, bottom_group; /* layer group holding top/bottom side */ /*! * \brief Parse a connection description from a string. * * Puts the element name in the string and the pin number in * the number. * * \return If a valid connection is found, it returns the number of characters * processed from the string, otherwise it returns 0. */ static bool ParseConnection (char *InString, char *ElementName, char *PinNum) { int i, j; /* copy element name portion */ for (j = 0; InString[j] != '\0' && InString[j] != '-'; j++) ElementName[j] = InString[j]; if (InString[j] == '-') { for (i = j; i > 0 && ElementName[i - 1] >= 'a'; i--); ElementName[i] = '\0'; for (i = 0, j++; InString[j] != '\0'; i++, j++) PinNum[i] = InString[j]; PinNum[i] = '\0'; return (false); } else { ElementName[j] = '\0'; Message (_("Bad net-list format encountered near: \"%s\"\n"), ElementName); return (true); } } /*! * \brief Find a particular pad from an element name and pin number. */ static bool FindPad (char *ElementName, char *PinNum, ConnectionType * conn, bool Same) { ElementType *element; GList *i; if ((element = SearchElementByName (PCB->Data, ElementName)) == NULL) return false; for (i = element->Pad; i != NULL; i = g_list_next (i)) { PadType *pad = i->data; if (NSTRCMP (PinNum, pad->Number) == 0 && (!Same || !TEST_FLAG (DRCFLAG, pad))) { conn->type = PAD_TYPE; conn->ptr1 = element; conn->ptr2 = pad; conn->group = TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_group : top_group; if (TEST_FLAG (EDGE2FLAG, pad)) { conn->X = pad->Point2.X; conn->Y = pad->Point2.Y; } else { conn->X = pad->Point1.X; conn->Y = pad->Point1.Y; } return true; } } for (i = element->Pin; i != NULL; i = g_list_next (i)) { PinType *pin = i->data; if (!TEST_FLAG (HOLEFLAG, pin) && pin->Number && NSTRCMP (PinNum, pin->Number) == 0 && (!Same || !TEST_FLAG (DRCFLAG, pin))) { conn->type = PIN_TYPE; conn->ptr1 = element; conn->ptr2 = pin; conn->group = bottom_group; /* any layer will do */ conn->X = pin->X; conn->Y = pin->Y; return true; } } return false; } /*! * \brief Parse a netlist menu entry and locate the corresponding pad. * * \return true if found, and fills in Connection information. */ bool SeekPad (LibraryEntryType * entry, ConnectionType * conn, bool Same) { int j; char ElementName[256]; char PinNum[256]; if (ParseConnection (entry->ListEntry, ElementName, PinNum)) return (false); for (j = 0; PinNum[j] != '\0'; j++); if (j == 0) { Message (_("Error! Netlist file is missing pin!\n" "white space after \"%s-\"\n"), ElementName); badnet = true; } else { if (FindPad (ElementName, PinNum, conn, Same)) return (true); if (Same) return (false); if (PinNum[j - 1] < '0' || PinNum[j - 1] > '9') { Message ("WARNING! Pin number ending with '%c'" " encountered in netlist file\n" "Probably a bad netlist file format\n", PinNum[j - 1]); } } Message (_("Can't find %s pin %s called for in netlist.\n"), ElementName, PinNum); return (false); } /*! * \brief Read the library-netlist build a true Netlist structure. */ NetListType * ProcNetlist (LibraryType *net_menu) { ConnectionType *connection; ConnectionType LastPoint; NetType *net; static NetListType *Wantlist = NULL; if (!net_menu->MenuN) return (NULL); FreeNetListMemory (Wantlist); free (Wantlist); badnet = false; /* find layer groups of the component side and solder side */ bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); top_group = GetLayerGroupNumberBySide (TOP_SIDE); Wantlist = (NetListType *)calloc (1, sizeof (NetListType)); if (Wantlist) { ALLPIN_LOOP (PCB->Data); { pin->Spare = NULL; CLEAR_FLAG (DRCFLAG, pin); } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { pad->Spare = NULL; CLEAR_FLAG (DRCFLAG, pad); } ENDALL_LOOP; MENU_LOOP (net_menu); { if (menu->Name[0] == '*' || menu->flag == 0) { badnet = true; continue; } net = GetNetMemory (Wantlist); if (menu->Style) { STYLE_LOOP (PCB); { if (style->Name && !NSTRCMP (style->Name, menu->Style)) { net->Style = style; break; } } END_LOOP; } else /* default to NULL if none found */ net->Style = NULL; ENTRY_LOOP (menu); { if (SeekPad (entry, &LastPoint, false)) { if (TEST_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2)) Message (_ ("Error! Element %s pin %s appears multiple times in the netlist file.\n"), NAMEONPCB_NAME ((ElementType *) LastPoint.ptr1), (LastPoint.type == PIN_TYPE) ? ((PinType *) LastPoint.ptr2)-> Number : ((PadType *) LastPoint.ptr2)->Number); else { connection = GetConnectionMemory (net); *connection = LastPoint; /* indicate expect net */ connection->menu = menu; /* mark as visited */ SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); if (LastPoint.type == PIN_TYPE) ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; else ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; } } else badnet = true; /* check for more pins with the same number */ for (; SeekPad (entry, &LastPoint, true);) { connection = GetConnectionMemory (net); *connection = LastPoint; /* indicate expect net */ connection->menu = menu; /* mark as visited */ SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); if (LastPoint.type == PIN_TYPE) ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; else ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; } } END_LOOP; } END_LOOP; } /* clear all visit marks */ ALLPIN_LOOP (PCB->Data); { CLEAR_FLAG (DRCFLAG, pin); } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { CLEAR_FLAG (DRCFLAG, pad); } ENDALL_LOOP; return (Wantlist); } /*! * \brief Copy all connections from one net into another and then remove * the first net from its netlist. */ static void TransferNet (NetListType *Netl, NetType *SourceNet, NetType *DestNet) { ConnectionType *conn; /* It would be worth checking if SourceNet is NULL here to avoid a segfault. Seb James. */ CONNECTION_LOOP (SourceNet); { conn = GetConnectionMemory (DestNet); *conn = *connection; } END_LOOP; DestNet->Style = SourceNet->Style; /* free the connection memory */ FreeNetMemory (SourceNet); /* remove SourceNet from its netlist */ *SourceNet = Netl->Net[--(Netl->NetN)]; /* zero out old garbage */ memset (&Netl->Net[Netl->NetN], 0, sizeof (NetType)); } static bool CheckShorts (LibraryMenuType *theNet) { bool newone, warn = false; PointerListType *generic = (PointerListType *)calloc (1, sizeof (PointerListType)); /* the first connection was starting point so * the menu is always non-null */ void **menu = GetPointerMemory (generic); *menu = theNet; ALLPIN_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, pin)) { warn = true; if (!pin->Spare) { Message (_("Warning! Net \"%s\" is shorted to %s pin %s\n"), &theNet->Name[2], UNKNOWN (NAMEONPCB_NAME (element)), UNKNOWN (pin->Number)); SET_FLAG (WARNFLAG, pin); continue; } newone = true; POINTER_LOOP (generic); { if (*ptr == pin->Spare) { newone = false; break; } } END_LOOP; if (newone) { menu = GetPointerMemory (generic); *menu = pin->Spare; Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"), &theNet->Name[2], &((LibraryMenuType *) (pin->Spare))->Name[2]); SET_FLAG (WARNFLAG, pin); } } } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, pad)) { warn = true; if (!pad->Spare) { Message (_("Warning! Net \"%s\" is shorted to %s pad %s\n"), &theNet->Name[2], UNKNOWN (NAMEONPCB_NAME (element)), UNKNOWN (pad->Number)); SET_FLAG (WARNFLAG, pad); continue; } newone = true; POINTER_LOOP (generic); { if (*ptr == pad->Spare) { newone = false; break; } } END_LOOP; if (newone) { menu = GetPointerMemory (generic); *menu = pad->Spare; Message (_("Warning! Net \"%s\" is shorted to net \"%s\"\n"), &theNet->Name[2], &((LibraryMenuType *) (pad->Spare))->Name[2]); SET_FLAG (WARNFLAG, pad); } } } ENDALL_LOOP; FreePointerListMemory (generic); free (generic); return (warn); } /*! * \brief Determine existing interconnections of the net and gather into * sub-nets. * * Initially the netlist has each connection in its own individual net * afterwards there can be many fewer nets with multiple connections * each. */ static bool GatherSubnets (NetListType *Netl, bool NoWarn, bool AndRats) { NetType *a, *b; ConnectionType *conn; Cardinal m, n; bool Warned = false; for (m = 0; Netl->NetN > 0 && m < Netl->NetN; m++) { a = &Netl->Net[m]; ClearFlagOnAllObjects (DRCFLAG, false); RatFindHook (a->Connection[0].type, a->Connection[0].ptr1, a->Connection[0].ptr2, a->Connection[0].ptr2, false, DRCFLAG, AndRats); /* now anybody connected to the first point has DRCFLAG set */ /* so move those to this subnet */ CLEAR_FLAG (DRCFLAG, (PinType *) a->Connection[0].ptr2); for (n = m + 1; n < Netl->NetN; n++) { b = &Netl->Net[n]; /* There can be only one connection in net b */ if (TEST_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2)) { CLEAR_FLAG (DRCFLAG, (PinType *) b->Connection[0].ptr2); TransferNet (Netl, b, a); /* back up since new subnet is now at old index */ n--; } } /* now add other possible attachment points to the subnet */ /* e.g. line end-points and vias */ /* don't add non-manhattan lines, the auto-router can't route to them */ ALLLINE_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, line)) { conn = GetConnectionMemory (a); conn->X = line->Point1.X; conn->Y = line->Point1.Y; conn->type = LINE_TYPE; conn->ptr1 = layer; conn->ptr2 = line; conn->group = GetLayerGroupNumberByPointer (layer); conn->menu = NULL; /* agnostic view of where it belongs */ conn = GetConnectionMemory (a); conn->X = line->Point2.X; conn->Y = line->Point2.Y; conn->type = LINE_TYPE; conn->ptr1 = layer; conn->ptr2 = line; conn->group = GetLayerGroupNumberByPointer (layer); conn->menu = NULL; } } ENDALL_LOOP; /* add polygons so the auto-router can see them as targets */ ALLPOLYGON_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, polygon)) { conn = GetConnectionMemory (a); /* make point on a vertex */ conn->X = polygon->Clipped->contours->head.point[0]; conn->Y = polygon->Clipped->contours->head.point[1]; conn->type = POLYGON_TYPE; conn->ptr1 = layer; conn->ptr2 = polygon; conn->group = GetLayerGroupNumberByPointer (layer); conn->menu = NULL; /* agnostic view of where it belongs */ } } ENDALL_LOOP; VIA_LOOP (PCB->Data); { if (TEST_FLAG (DRCFLAG, via)) { conn = GetConnectionMemory (a); conn->X = via->X; conn->Y = via->Y; conn->type = VIA_TYPE; conn->ptr1 = via; conn->ptr2 = via; conn->group = bottom_group; } } END_LOOP; if (!NoWarn) Warned |= CheckShorts (a->Connection[0].menu); } ClearFlagOnAllObjects (DRCFLAG, false); return (Warned); } /*! * \brief Draw a rat net (tree) having the shortest lines. * * This also frees the subnet memory as they are consumed. * * \note The \c Netl we are passed is NOT the main netlist - it's the * connectivity for ONE net. * It represents the CURRENT connectivity state for the net, with each * Netl->Net[N] representing one copper-connected subset of the net. * * Everything inside the NetList Netl should be connected together. * * Each Net in \c Netl is a group of Connections which are already * connected together somehow, either by real wires or by rats we've * already drawn. * * Each Connection is a vertex within that blob of connected items. * * This loop finds the closest vertex pairs between each blob and draws * rats that merge the blobs until there's just one big blob. * * Just to clarify, with some examples: * * Each \c Netl is one full net from a netlist, like from gnetlist. * * Each Netl->Net[N] is a subset of that net that's already * physically connected on the pcb. * * So a new design with no traces yet, would have a huge list of Net[N], * each with one pin in it. * * A fully routed design would have one Net[N] with all the pins * (for that net) in it. */ static bool DrawShortestRats (NetListType *Netl, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *)) { RatType *line; register float distance, temp; register ConnectionType *conn1, *conn2, *firstpoint, *secondpoint; PolygonType *polygon; bool changed = false; bool havepoints; Cardinal n, m, j; NetType *next, *subnet, *theSubnet = NULL; /* This is just a sanity check, to make sure we're passed * *something*. */ if (!Netl || Netl->NetN < 1) return false; /* * We keep doing this do/while loop until everything's connected. * I.e. once per rat we add. */ distance = 0.0; havepoints = true; /* so we run the loop at least once */ while (Netl->NetN > 1 && havepoints) { /* This is the top of the "find one rat" logic. */ havepoints = false; firstpoint = secondpoint = NULL; /* Test Net[0] vs Net[N] for N=1..max. Find the shortest distance between any two points in different blobs. */ subnet = &Netl->Net[0]; for (j = 1; j < Netl->NetN; j++) { /* * Scan between Net[0] blob (subnet) and Net[N] blob (next). * Note the shortest distance we find. */ next = &Netl->Net[j]; for (n = subnet->ConnectionN - 1; n != -1; n--) { conn1 = &subnet->Connection[n]; for (m = next->ConnectionN - 1; m != -1; m--) { conn2 = &next->Connection[m]; /* * At this point, conn1 and conn2 are two pins in * different blobs of the same net. See how far * apart they are, and if they're "closer" than what * we already have. */ /* * Prefer to connect Connections over polygons to the * polygons (ie assume the user wants a via to a plane, * not a daisy chain). Further prefer to pick an existing * via in the Net to make that connection. */ if (conn1->type == POLYGON_TYPE && (polygon = (PolygonType *)conn1->ptr2) && !(distance == 0 && firstpoint && firstpoint->type == VIA_TYPE) && IsPointInPolygonIgnoreHoles (conn2->X, conn2->Y, polygon)) { distance = 0; firstpoint = conn2; secondpoint = conn1; theSubnet = next; havepoints = true; } else if (conn2->type == POLYGON_TYPE && (polygon = (PolygonType *)conn2->ptr2) && !(distance == 0 && firstpoint && firstpoint->type == VIA_TYPE) && IsPointInPolygonIgnoreHoles (conn1->X, conn1->Y, polygon)) { distance = 0; firstpoint = conn1; secondpoint = conn2; theSubnet = next; havepoints = true; } else if ((temp = SQUARE (conn1->X - conn2->X) + SQUARE (conn1->Y - conn2->Y)) < distance || !firstpoint) { distance = temp; firstpoint = conn1; secondpoint = conn2; theSubnet = next; havepoints = true; } } } } /* * If HAVEPOINTS is true, we've found a pair of points in two * separate blobs of the net, and need to connect them together. */ if (havepoints) { if (funcp) { (*funcp) (firstpoint, secondpoint, subnet->Style); } else { /* found the shortest distance subnet, draw the rat */ if ((line = CreateNewRat (PCB->Data, firstpoint->X, firstpoint->Y, secondpoint->X, secondpoint->Y, firstpoint->group, secondpoint->group, Settings.RatThickness, NoFlags ())) != NULL) { if (distance == 0) SET_FLAG (VIAFLAG, line); AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line); DrawRat (line); changed = true; } } /* copy theSubnet into the current subnet */ TransferNet (Netl, theSubnet, subnet); } } /* presently nothing to do with the new subnet */ /* so we throw it away and free the space */ FreeNetMemory (&Netl->Net[--(Netl->NetN)]); /* Sadly adding a rat line messes up the sorted arrays in connection finder */ /* hace: perhaps not necessarily now that they aren't stored in normal layers */ if (changed) { FreeConnectionLookupMemory (); InitConnectionLookup (); } return (changed); } /*! * \brief AddAllRats puts the rats nest into the layout from the loaded * netlist. * * If SelectedOnly is true, it will only draw rats to selected pins and * pads. */ bool AddAllRats (bool SelectedOnly, void (*funcp) (register ConnectionType *, register ConnectionType *, register RouteStyleType *)) { NetListType *Nets, *Wantlist; NetType *lonesome; ConnectionType *onepin; bool changed, Warned = false; /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Wantlist = ProcNetlist (&PCB->NetlistLib); if (!Wantlist) { Message (_("Can't add rat lines because no netlist is loaded.\n")); return (false); } changed = false; /* initialize finding engine */ InitConnectionLookup (); Nets = (NetListType *)calloc (1, sizeof (NetListType)); /* now we build another netlist (Nets) for each * net in Wantlist that shows how it actually looks now, * then fill in any missing connections with rat lines. * * we first assume each connection is separate * (no routing), then gather them into groups * if the net is all routed, the new netlist (Nets) * will have only one net entry. * Note that DrawShortestRats consumes all nets * from Nets, so *Nets is empty after the * DrawShortestRats call */ NET_LOOP (Wantlist); { CONNECTION_LOOP (net); { if (!SelectedOnly || TEST_FLAG (SELECTEDFLAG, (PinType *) connection->ptr2)) { lonesome = GetNetMemory (Nets); onepin = GetConnectionMemory (lonesome); *onepin = *connection; lonesome->Style = net->Style; } } END_LOOP; Warned |= GatherSubnets (Nets, SelectedOnly, true); if (Nets->NetN > 0) changed |= DrawShortestRats (Nets, funcp); } END_LOOP; FreeNetListMemory (Nets); free (Nets); FreeConnectionLookupMemory (); if (funcp) return (true); if (Warned || changed) Draw (); if (Warned) Settings.RatWarn = true; if (changed) { IncrementUndoSerialNumber (); if (PCB->Data->RatN > 0) { Message ("%d rat line%s remaining\n", PCB->Data->RatN, PCB->Data->RatN > 1 ? "s" : ""); } return (true); } if (!SelectedOnly && !Warned) { if (!PCB->Data->RatN && !badnet) Message (_("Congratulations!!\n" "The layout is complete and has no shorted nets.\n")); else Message (_("Nothing more to add, but there are\n" "either rat-lines in the layout, disabled nets\n" "in the net-list, or missing components\n")); } return (false); } /*! * \todo This is copied in large part from AddAllRats above; for * maintainability, AddAllRats probably wants to be tweaked to use this * version of the code so that we don't have duplication. */ NetListListType CollectSubnets (bool SelectedOnly) { NetListListType result = { 0, 0, NULL }; NetListType *Nets, *Wantlist; NetType *lonesome; ConnectionType *onepin; /* the netlist library has the text form * ProcNetlist fills in the Netlist * structure the way the final routing * is supposed to look */ Wantlist = ProcNetlist (&PCB->NetlistLib); if (!Wantlist) { Message (_("Can't add rat lines because no netlist is loaded.\n")); return result; } /* initialize finding engine */ InitConnectionLookup (); /* now we build another netlist (Nets) for each * net in Wantlist that shows how it actually looks now, * then fill in any missing connections with rat lines. * * we first assume each connection is separate * (no routing), then gather them into groups * if the net is all routed, the new netlist (Nets) * will have only one net entry. * Note that DrawShortestRats consumes all nets * from Nets, so *Nets is empty after the * DrawShortestRats call */ NET_LOOP (Wantlist); { Nets = GetNetListMemory (&result); CONNECTION_LOOP (net); { if (!SelectedOnly || TEST_FLAG (SELECTEDFLAG, (PinType *) connection->ptr2)) { lonesome = GetNetMemory (Nets); onepin = GetConnectionMemory (lonesome); *onepin = *connection; lonesome->Style = net->Style; } } END_LOOP; /* Note that AndRats is *FALSE* here! */ GatherSubnets (Nets, SelectedOnly, false); } END_LOOP; FreeConnectionLookupMemory (); return result; } /*! * \brief Check to see if a particular name is the name of an already * existing rats line. */ static int rat_used (char *name) { if (name == NULL) return -1; MENU_LOOP (&PCB->NetlistLib); { if (menu->Name && (strcmp (menu->Name, name) == 0)) return 1; } END_LOOP; return 0; } /*! * \brief This function is moved from the original netlist.c as * part of the gui code separation for the Gtk port. */ RatType * AddNet (void) { static int ratDrawn = 0; char name1[256], *name2; Cardinal group1, group2; char ratname[22]; int found; void *ptr1, *ptr2, *ptr3; LibraryMenuType *menu; LibraryEntryType *entry; if (Crosshair.AttachedLine.Point1.X == Crosshair.AttachedLine.Point2.X && Crosshair.AttachedLine.Point1.Y == Crosshair.AttachedLine.Point2.Y) return (NULL); found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, 5); if (found == NO_TYPE) { Message (_("No pad/pin under rat line\n")); return (NULL); } if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0) { Message (_("You must name the starting element first\n")); return (NULL); } /* will work for pins to since the FLAG is common */ group1 = GetLayerGroupNumberBySide ( TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE); strcpy (name1, ConnectionName (found, ptr1, ptr2)); found = SearchObjectByLocation (PAD_TYPE | PIN_TYPE, &ptr1, &ptr2, &ptr3, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, 5); if (found == NO_TYPE) { Message (_("No pad/pin under rat line\n")); return (NULL); } if (NAMEONPCB_NAME ((ElementType *) ptr1) == NULL || *NAMEONPCB_NAME ((ElementType *) ptr1) == 0) { Message (_("You must name the ending element first\n")); return (NULL); } group2 = GetLayerGroupNumberBySide ( TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? BOTTOM_SIDE : TOP_SIDE); name2 = ConnectionName (found, ptr1, ptr2); menu = netnode_to_netname (name1); if (menu) { if (netnode_to_netname (name2)) { Message (_ ("Both connections already in netlist - cannot merge nets\n")); return (NULL); } entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name2); netnode_to_netname (name2); goto ratIt; } /* ok, the first name did not belong to a net */ menu = netnode_to_netname (name2); if (menu) { entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name1); netnode_to_netname (name1); goto ratIt; } /* * neither belong to a net, so create a new one. * * before creating a new rats here, we need to search * for a unique name. */ sprintf (ratname, " ratDrawn%i", ++ratDrawn); while (rat_used (ratname)) { sprintf (ratname, " ratDrawn%i", ++ratDrawn); } menu = GetLibraryMenuMemory (&PCB->NetlistLib); menu->Name = strdup (ratname); entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name1); entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup (name2); menu->flag = 1; ratIt: NetlistChanged (0); return (CreateNewRat (PCB->Data, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, group1, group2, Settings.RatThickness, NoFlags ())); } /*! * \brief This function is moved from the original netlist.c as * part of the gui code separation for the Gtk port. */ char * ConnectionName (int type, void *ptr1, void *ptr2) { static char name[256]; char *num; switch (type) { case PIN_TYPE: num = ((PinType *) ptr2)->Number; break; case PAD_TYPE: num = ((PadType *) ptr2)->Number; break; default: return (NULL); } strcpy (name, UNKNOWN (NAMEONPCB_NAME ((ElementType *) ptr1))); strcat (name, "-"); strcat (name, UNKNOWN (num)); return (name); } pcb-4.2.2/src/compat.c0000664000076400007640000000416713434555140011450 00000000000000/*! * \file src/compat.c * * \brief . * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2004, 2006 Dan McMahill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "compat.h" #include "global.h" #ifdef HAVE_LIBDMALLOC #include #endif #ifndef HAVE_EXPF float expf (float x) { return (float) exp ((double) x); } #endif #ifndef HAVE_LOGF float logf (float x) { return (float) log ((double) x); } #endif #ifndef HAVE_RANDOM long random (void) { return (long) rand (); } #endif #if !defined(HAVE_DLFCN_H) && defined(WIN32) #define WIN32_LEAN_AND_MEAN #include void * dlopen (const char * f, int ATTRIBUTE_UNUSED flag) { return LoadLibrary (f); } void dlclose (void * h) { FreeLibrary ((HINSTANCE) h); } char * dlerror () { static LPVOID lpMsgBuf = NULL; DWORD dw; /* free the error message buffer */ if (lpMsgBuf) LocalFree (lpMsgBuf); /* get the error code */ dw = GetLastError(); /* get the corresponding error message */ FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); return (char *) lpMsgBuf; } void * dlsym (void *handle, const char *symbol) { return (void *) GetProcAddress((HMODULE) handle, symbol); } #endif pcb-4.2.2/src/dbus.c0000664000076400007640000002524013434555140011115 00000000000000/*! * \file src/dbus.c * * \brief D-Bus IPC logic * * D-Bus code originally derrived from example-service.c in the * dbus-glib bindings. * * PCB, an interactive printed circuit board editor * * Copyright (C) 2006 University of Cambridge * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #define DBUS_API_SUBJECT_TO_CHANGE #include #include #include "dbus.h" #include "dbus-pcbmain.h" #include "dbus-introspect.h" #include "global.h" #include "data.h" /* For lrealpath */ #include "lrealpath.h" #define PCB_DBUS_CANONICAL_NAME "org.seul.geda.pcb" #define PCB_DBUS_OBJECT_PATH "/org/seul/geda/pcb" #define PCB_DBUS_INTERFACE "org.seul.geda.pcb" #define PCB_DBUS_ACTIONS_INTERFACE "org.seul.geda.pcb.actions" static DBusConnection *pcb_dbus_conn; static DBusHandlerResult handle_get_filename (DBusConnection * connection, DBusMessage * message, void *data) { DBusMessage *reply; DBusMessageIter iter; DBusHandlerResult result; char *filename; result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; // TODO: Should check the message signature matches what we expect? reply = dbus_message_new_method_return (message); if (reply == NULL) { fprintf (stderr, "pcb_dbus: Couldn't create reply message\n"); return result; } dbus_message_iter_init_append (reply, &iter); if (PCB->Filename) filename = lrealpath (PCB->Filename); else filename = NULL; if (filename == NULL) { #ifdef DEBUG fprintf (stderr, "pcb_dbus: DEBUG: Couldn't get working filename, assuming none\n"); #endif filename = strdup (""); if (filename == NULL) { fprintf (stderr, "pcb_dbus: Couldn't strdup( \"\" ) for the filename\n"); goto out; } } if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &filename)) { fprintf (stderr, "pcb_dbus: Couldn't append return filename string to message reply, Out Of Memory!\n"); free (filename); goto out; } free (filename); if (!dbus_connection_send (connection, reply, NULL)) { fprintf (stderr, "pcb_dbus: Couldn't send message, Out Of Memory!\n"); goto out; } result = DBUS_HANDLER_RESULT_HANDLED; out: dbus_message_unref (reply); return result; } static DBusHandlerResult handle_exec_action (DBusConnection * connection, DBusMessage * message, void *data) { DBusMessage *reply; DBusMessageIter iter; DBusHandlerResult result; DBusError err; dbus_uint32_t retval; char *action_name; char **argv; int argc; #ifdef DEBUG int i; #endif result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; // TODO: Should check the message signature matches what we expect? // initialise the error struct dbus_error_init (&err); /* DON'T FREE action_name, as it belongs to DBUS, * DO FREE argv, using dbus_free_string_array() */ argv = NULL; if (!dbus_message_get_args (message, &err, DBUS_TYPE_STRING, &action_name, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &argv, &argc, DBUS_TYPE_INVALID)) { fprintf (stderr, "Failed to read method arguments\n"); if (argv) dbus_free_string_array (argv); return result; } #ifdef DEBUG fprintf (stderr, "pcb_dbus: DEBUG: Executing action: %s(", action_name); if (argc > 0) fprintf (stderr, " \"%s\"", argv[0]); for (i = 1; i < argc; i++) fprintf (stderr, ", \"%s\"", argv[i]); fprintf (stderr, " )\n"); #endif // TODO: Proper return value from actions hid_actionv (action_name, argc, argv); retval = 0; dbus_free_string_array (argv); reply = dbus_message_new_method_return (message); if (reply == NULL) { fprintf (stderr, "pcb_dbus: Couldn't create reply message\n"); return result; } dbus_message_iter_init_append (reply, &iter); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &retval)) { fprintf (stderr, "pcb_dbus: Couldn't sent message, Out Of Memory!\n"); goto out; } if (!dbus_connection_send (connection, reply, NULL)) { fprintf (stderr, "pcb_dbus: Couldn't send message, Out Of Memory!\n"); goto out; } result = DBUS_HANDLER_RESULT_HANDLED; out: dbus_message_unref (reply); return result; } static DBusHandlerResult handle_introspect (DBusConnection * connection, DBusMessage * message, void *data) { DBusMessage *reply; DBusMessageIter iter; DBusHandlerResult result; result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; reply = dbus_message_new_method_return (message); if (reply == NULL) { fprintf (stderr, "pcb_dbus: Couldn't create reply message\n"); return result; } dbus_message_iter_init_append (reply, &iter); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &pcb_dbus_introspect_xml)) { fprintf (stderr, "pcb_dbus: Couldn't add introspect XML to message return\n"); goto out; } if (!dbus_connection_send (pcb_dbus_conn, reply, NULL)) { fprintf (stderr, "pcb_dbus: Couldn't queue reply message for sending\n"); goto out; } result = DBUS_HANDLER_RESULT_HANDLED; out: dbus_message_unref (reply); return result; } static void unregister_dbus_handler (DBusConnection * connection, void *data) { } static DBusHandlerResult handle_dbus_message (DBusConnection * connection, DBusMessage * message, void *data) { int msg_type; msg_type = dbus_message_get_type (message); switch (msg_type) { case DBUS_MESSAGE_TYPE_METHOD_CALL: { const char *method_name; const char *interface_name; method_name = dbus_message_get_member (message); if (method_name == NULL) { fprintf (stderr, "pcb_dbus: Method had no name specified\n"); break; } interface_name = dbus_message_get_interface (message); if (interface_name == NULL) { fprintf (stderr, "pcb_dbus: Method had no interface specified\n"); break; } if (strcmp (interface_name, PCB_DBUS_INTERFACE) == 0) { if (strcmp (method_name, "GetFilename") == 0) { return handle_get_filename (connection, message, data); } fprintf (stderr, "pcb_dbus: Interface '%s' has no method '%s'\n", interface_name, method_name); break; } else if (strcmp (interface_name, PCB_DBUS_ACTIONS_INTERFACE) == 0) { if (strcmp (method_name, "ExecAction") == 0) { return handle_exec_action (connection, message, data); } fprintf (stderr, "pcb_dbus: Interface '%s' has no method '%s'\n", interface_name, method_name); break; } else if (strcmp (interface_name, DBUS_INTERFACE_INTROSPECTABLE) == 0) { if (strcmp (method_name, "Introspect") == 0) { return handle_introspect (connection, message, data); } fprintf (stderr, "pcb_dbus: Interface '%s' has no method '%s'\n", interface_name, method_name); break; } else { fprintf (stderr, "pcb_dbus: Interface '%s' was not recognised\n", interface_name); break; } } break; case DBUS_MESSAGE_TYPE_METHOD_RETURN: fprintf (stderr, "pcb_dbus: DBUG: Method return message\n"); // WON'T ACTUALLY BE ANY UNLESS WE MAKE AN ASYNCRONOUS CALL? break; case DBUS_MESSAGE_TYPE_ERROR: fprintf (stderr, "pcb_dbus: DEBUG: Error message\n"); // HOPE NOT! break; case DBUS_MESSAGE_TYPE_SIGNAL: fprintf (stderr, "pcb_dbus: DEBUG: Signal message\n"); // NONE AT PRESENT break; default: fprintf (stderr, "pcb_dbus: DEBUG: Message type wasn't one we know about!\n"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } /*! * \brief Carry out all actions to setup the D-Bus and register * appropriate callbacks. */ void pcb_dbus_setup (void) { DBusError err; int ret; const DBusObjectPathVTable object_vtable = { unregister_dbus_handler, handle_dbus_message, NULL, NULL, NULL, NULL }; // Initialise the error variable dbus_error_init (&err); // Connect to the bus pcb_dbus_conn = dbus_bus_get_private (DBUS_BUS_SESSION, &err); if (dbus_error_is_set (&err)) { fprintf (stderr, "pcb_dbus: DBus connection Error (%s)\n", err.message); dbus_error_free (&err); } if (pcb_dbus_conn == NULL) return; // Request the canonical name for PCB on the bus ret = dbus_bus_request_name (pcb_dbus_conn, PCB_DBUS_CANONICAL_NAME, DBUS_NAME_FLAG_REPLACE_EXISTING, &err); if (dbus_error_is_set (&err)) { fprintf (stderr, "pcb_dbus: DBus name error (%s)\n", err.message); dbus_error_free (&err); } if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER && ret != DBUS_REQUEST_NAME_REPLY_IN_QUEUE) { fprintf (stderr, "pcb_dbus: Couldn't gain ownership or queued ownership of the canonical DBus name\n"); return; } if (!dbus_connection_register_object_path (pcb_dbus_conn, PCB_DBUS_OBJECT_PATH, &object_vtable, NULL // void * user_data )) { fprintf (stderr, "pcb_dbus: Couldn't register DBUS handler for %s\n", PCB_DBUS_OBJECT_PATH); return; } // Setup intergration with the pcb mainloop pcb_dbus_connection_setup_with_mainloop (pcb_dbus_conn); // dbus_error_free(&err); return; } /*! * \brief Carry out all actions to finalise the D-Bus connection. */ void pcb_dbus_finish (void) { DBusError err; // Initialise the error variable dbus_error_init (&err); // TODO: Could emit a "goodbye" signal here? dbus_connection_flush (pcb_dbus_conn); dbus_connection_unregister_object_path (pcb_dbus_conn, PCB_DBUS_OBJECT_PATH); dbus_bus_release_name (pcb_dbus_conn, PCB_DBUS_CANONICAL_NAME, &err); dbus_error_free (&err); pcb_dbus_connection_finish_with_mainloop (pcb_dbus_conn); dbus_connection_close (pcb_dbus_conn); dbus_connection_unref (pcb_dbus_conn); // Call DBus shutdown. This doesn't work with shared connections, // only private ones (like we took out earlier). // If any future module / plugin to PCB wants to use DBus too, // we must remove this call. DBus will get shut-down when the app exits. dbus_shutdown (); } pcb-4.2.2/src/find.h0000664000076400007640000000503613533277055011114 00000000000000/*! * \file src/find.h * * \brief Prototypes for connection search routines. * *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_FIND_H #define PCB_FIND_H #include /* needed to define 'FILE *' */ #include "global.h" /* --------------------------------------------------------------------------- * some local defines */ #define LOOKUP_FIRST \ (PIN_TYPE | PAD_TYPE) #define LOOKUP_MORE \ (VIA_TYPE | LINE_TYPE | RATLINE_TYPE | POLYGON_TYPE | ARC_TYPE) #define SILK_TYPE \ (LINE_TYPE | ARC_TYPE | POLYGON_TYPE) bool LineLineIntersect (LineType *, LineType *); bool LineArcIntersect (LineType *, ArcType *); bool PinLineIntersect (PinType *, LineType *); bool LinePadIntersect (LineType *, PadType *); bool ArcPadIntersect (ArcType *, PadType *); void LookupElementConnections (ElementType *, FILE *); void LookupConnectionsToAllElements (FILE *); void LookupConnection (Coord, Coord, bool, Coord, int, bool AndRats); void LookupUnusedPins (FILE *); void InitConnectionLookup (void); void FreeConnectionLookupMemory (void); void RatFindHook (int, void *, void *, void *, bool, int flag, bool); void LookupConnectionByPin (int , void *); /* remove these prototypes later */ bool ListStart(int, void*, void*, void*, int); bool DoIt(int, Coord, bool, bool, bool); void DumpList(void); void start_do_it_and_dump(int, void*, void*, void*, int, bool, Coord, bool); bool IsArcInPolygon (ArcType *, PolygonType *); bool IsLineInPolygon (LineType *, PolygonType *); bool IsPadInPolygon (PadType *, PolygonType *); bool IsPinInPolygon (PinType *, PolygonType *); bool IsPolygonInPolygon (PolygonType *, PolygonType *); #endif pcb-4.2.2/src/change.h0000664000076400007640000001006113434555140011405 00000000000000/*! * \file src/change.h * * \brief Prototypes to change object properties. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_CHANGE_H #define PCB_CHANGE_H #include "global.h" /* --------------------------------------------------------------------------- * some defines */ #define CHANGENAME_TYPES \ (VIA_TYPE | PIN_TYPE | PAD_TYPE | TEXT_TYPE | ELEMENT_TYPE | ELEMENTNAME_TYPE | LINE_TYPE) #define CHANGESIZE_TYPES \ (POLYGON_TYPE | VIA_TYPE | PIN_TYPE | PAD_TYPE | LINE_TYPE | \ ARC_TYPE | TEXT_TYPE | ELEMENTNAME_TYPE | ELEMENT_TYPE) #define CHANGE2NDSIZE_TYPES \ (VIA_TYPE | PIN_TYPE | ELEMENT_TYPE) /* We include polygons here only to inform the user not to do it that way. */ #define CHANGECLEARSIZE_TYPES \ (PIN_TYPE | PAD_TYPE | VIA_TYPE | LINE_TYPE | ARC_TYPE | POLYGON_TYPE) #define CHANGESQUARE_TYPES \ (ELEMENT_TYPE | PIN_TYPE | PAD_TYPE) #define CHANGEOCTAGON_TYPES \ (ELEMENT_TYPE | PIN_TYPE | VIA_TYPE) #define CHANGEJOIN_TYPES \ (ARC_TYPE | LINE_TYPE | TEXT_TYPE) #define CHANGETHERMAL_TYPES \ (PIN_TYPE | VIA_TYPE) #define CHANGEMASKSIZE_TYPES \ (PIN_TYPE | VIA_TYPE | PAD_TYPE) bool ChangeLayoutName (char *); bool ChangeLayerName (LayerType *, char *); bool ChangeSelectedSize (int, Coord, bool); bool ChangeSelectedClearSize (int, Coord, bool); bool ChangeSelected2ndSize (int, Coord, bool); bool ChangeSelectedMaskSize (int, Coord, bool); bool ChangeSelectedJoin (int); bool SetSelectedJoin (int); bool ClrSelectedJoin (int); bool ChangeSelectedSquare (int); bool SetSelectedSquare (int); bool ClrSelectedSquare (int); bool ChangeSelectedThermals (int, int); bool ChangeSelectedViaLayers (int, int); bool ChangeSelectedHole (void); bool ChangeSelectedPaste (void); bool ChangeSelectedOctagon (int); bool SetSelectedOctagon (int); bool ClrSelectedOctagon (int); bool ChangeSelectedElementSide (void); bool ChangeElementSide (ElementType *, Coord); bool ChangeHole (PinType *); bool ChangePaste (PadType *); bool ChangeObjectSize (int, void *, void *, void *, Coord, bool); bool ChangeObjectThermal (int, void *, void *, void *, int); bool ChangeObjectViaLayers (void *, void *, void *, int, int); bool ChangeObjectClearSize (int, void *, void *, void *, Coord, bool); bool ChangeObject2ndSize (int, void *, void *, void *, Coord, bool, bool); bool ChangeObjectMaskSize (int, void *, void *, void *, Coord, bool); bool ChangeObjectJoin (int, void *, void *, void *); bool SetObjectJoin (int, void *, void *, void *); bool ClrObjectJoin (int, void *, void *, void *); bool ChangeObjectSquare (int, void *, void *, void *); bool SetObjectSquare (int, void *, void *, void *); bool ClrObjectSquare (int, void *, void *, void *); bool ChangeObjectOctagon (int, void *, void *, void *); bool SetObjectOctagon (int, void *, void *, void *); bool ClrObjectOctagon (int, void *, void *, void *); void *ChangeObjectName (int, void *, void *, void *, char *); void *QueryInputAndChangeObjectName (int, void *, void *, void *); void ChangePCBSize (Coord, Coord); char *ChangeElementText (PCBType *pcb, DataType *data, ElementType *Element, int which, char *new_name); #endif pcb-4.2.2/src/dbus.xml0000664000076400007640000000147211660653114011473 00000000000000 pcb-4.2.2/src/line.c0000664000076400007640000003053113434555140011106 00000000000000/*! * \file src/line.c * * \brief Routines for inserting points into objects. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 2004 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "global.h" #include "data.h" #include "crosshair.h" #include "find.h" #include "line.h" #include "misc.h" #include "rtree.h" #ifdef HAVE_LIBDMALLOC #include #endif static double drc_lines (PointType *end, bool way); /*! * \brief Adjust the attached line to 45 degrees if necessary. */ void AdjustAttachedLine (void) { AttachedLineType *line = &Crosshair.AttachedLine; /* I need at least one point */ if (line->State == STATE_FIRST) return; /* don't draw outline when ctrl key is pressed */ if (Settings.Mode == LINE_MODE && gui->control_is_pressed ()) { line->draw = false; return; } else line->draw = true; /* no 45 degree lines required */ if (PCB->RatDraw || TEST_FLAG (ALLDIRECTIONFLAG, PCB)) { line->Point2.X = Crosshair.X; line->Point2.Y = Crosshair.Y; return; } FortyFiveLine (line); } /*! * \brief Makes the attached line fit into a 45 degree direction. * * Directions:\n
           4
          5 3
         6   2
          7 1
           0
*/ void FortyFiveLine (AttachedLineType *Line) { Coord dx, dy, min, max; unsigned direction = 0; double m; /* first calculate direction of line */ dx = Crosshair.X - Line->Point1.X; dy = Crosshair.Y - Line->Point1.Y; /* zero length line, don't draw anything */ if (dx == 0 && dy == 0) return; if (dx == 0) direction = dy > 0 ? 0 : 4; else { m = (double)dy / (double)dx; direction = 2; if (m > TAN_30_DEGREE) direction = m > TAN_60_DEGREE ? 0 : 1; else if (m < -TAN_30_DEGREE) direction = m < -TAN_60_DEGREE ? 4 : 3; } if (dx < 0) direction += 4; dx = abs (dx); dy = abs (dy); min = MIN (dx, dy); max = MAX (dx, dy); /* now set up the second pair of coordinates */ switch (direction) { case 0: Line->Point2.X = Line->Point1.X; Line->Point2.Y = Line->Point1.Y + max; break; case 4: Line->Point2.X = Line->Point1.X; Line->Point2.Y = Line->Point1.Y - max; break; case 2: Line->Point2.X = Line->Point1.X + max; Line->Point2.Y = Line->Point1.Y; break; case 6: Line->Point2.X = Line->Point1.X - max; Line->Point2.Y = Line->Point1.Y; break; case 1: Line->Point2.X = Line->Point1.X + min; Line->Point2.Y = Line->Point1.Y + min; break; case 3: Line->Point2.X = Line->Point1.X + min; Line->Point2.Y = Line->Point1.Y - min; break; case 5: Line->Point2.X = Line->Point1.X - min; Line->Point2.Y = Line->Point1.Y - min; break; case 7: Line->Point2.X = Line->Point1.X - min; Line->Point2.Y = Line->Point1.Y + min; break; } } /*! * \brief Adjusts the insert lines to make them 45 degrees as necessary. */ void AdjustTwoLine (bool way) { Coord dx, dy; AttachedLineType *line = &Crosshair.AttachedLine; if (Crosshair.AttachedLine.State == STATE_FIRST) return; /* don't draw outline when ctrl key is pressed */ if (gui->control_is_pressed ()) { line->draw = false; return; } else line->draw = true; if (TEST_FLAG (ALLDIRECTIONFLAG, PCB)) { line->Point2.X = Crosshair.X; line->Point2.Y = Crosshair.Y; return; } /* swap the modes if shift is held down */ if (gui->shift_is_pressed ()) way = !way; dx = Crosshair.X - line->Point1.X; dy = Crosshair.Y - line->Point1.Y; if (!way) { if (abs (dx) > abs (dy)) { line->Point2.X = Crosshair.X - SGN (dx) * abs (dy); line->Point2.Y = line->Point1.Y; } else { line->Point2.X = line->Point1.X; line->Point2.Y = Crosshair.Y - SGN (dy) * abs (dx); } } else { if (abs (dx) > abs (dy)) { line->Point2.X = line->Point1.X + SGN (dx) * abs (dy); line->Point2.Y = Crosshair.Y; } else { line->Point2.X = Crosshair.X; line->Point2.Y = line->Point1.Y + SGN (dy) * abs (dx);; } } } struct drc_info { LineType *line; bool bottom_side; bool top_side; jmp_buf env; }; static int drcVia_callback (const BoxType * b, void *cl) { PinType *via = (PinType *) b; struct drc_info *i = (struct drc_info *) cl; if (!TEST_FLAG (FOUNDFLAG, via) && PinLineIntersect (via, i->line)) longjmp (i->env, 1); return 1; } static int drcPad_callback (const BoxType * b, void *cl) { PadType *pad = (PadType *) b; struct drc_info *i = (struct drc_info *) cl; if (TEST_FLAG (ONSOLDERFLAG, pad) == i->bottom_side && !TEST_FLAG (FOUNDFLAG, pad) && LinePadIntersect (i->line, pad)) longjmp (i->env, 1); return 1; } static int drcLine_callback (const BoxType * b, void *cl) { LineType *line = (LineType *) b; struct drc_info *i = (struct drc_info *) cl; if (!TEST_FLAG (FOUNDFLAG, line) && LineLineIntersect (line, i->line)) longjmp (i->env, 1); return 1; } static int drcArc_callback (const BoxType * b, void *cl) { ArcType *arc = (ArcType *) b; struct drc_info *i = (struct drc_info *) cl; if (!TEST_FLAG (FOUNDFLAG, arc) && LineArcIntersect (i->line, arc)) longjmp (i->env, 1); return 1; } /*! * \brief drc_lines() checks for intersectors against two lines and * adjusts the end point until there is no intersection or * it winds up back at the start. * * If way is false it checks straight start, 45 end lines, otherwise it * checks 45 start, straight end. * * It returns the straight-line length of the best answer, and * changes the position of the input point to the best answer. */ static double drc_lines (PointType *end, bool way) { double f, s, f2, s2, len, best; Coord dx, dy, temp, last, length; Coord temp2, last2, length2; LineType line1, line2; Cardinal group; struct drc_info info; bool two_lines, x_is_long, blocker; PointType ans; f = 1.0; s = 0.5; last = -1; line1.Flags = line2.Flags = NoFlags (); line1.Thickness = Settings.LineThickness + 2 * PCB->Bloat; line2.Thickness = line1.Thickness; line1.Clearance = line2.Clearance = 0; line1.Point1.X = Crosshair.AttachedLine.Point1.X; line1.Point1.Y = Crosshair.AttachedLine.Point1.Y; dy = end->Y - line1.Point1.Y; dx = end->X - line1.Point1.X; if (abs (dx) > abs (dy)) { x_is_long = true; length = abs (dx); } else { x_is_long = false; length = abs (dy); } group = GetLayerGroupNumberByNumber (INDEXOFCURRENT); info.bottom_side = (GetLayerGroupNumberBySide (BOTTOM_SIDE) == group); info.top_side = (GetLayerGroupNumberBySide (TOP_SIDE) == group); temp = length; /* assume the worst */ best = 0.0; ans.X = line1.Point1.X; ans.Y = line1.Point1.Y; while (length != last) { last = length; if (x_is_long) { dx = SGN (dx) * length; dy = end->Y - line1.Point1.Y; length2 = abs (dy); } else { dy = SGN (dy) * length; dx = end->X - line1.Point1.X; length2 = abs (dx); } temp2 = length2; f2 = 1.0; s2 = 0.5; last2 = -1; blocker = true; while (length2 != last2) { if (x_is_long) dy = SGN (dy) * length2; else dx = SGN (dx) * length2; two_lines = true; if (abs (dx) > abs (dy) && x_is_long) { line1.Point2.X = line1.Point1.X + (way ? SGN (dx) * abs (dy) : dx - SGN (dx) * abs (dy)); line1.Point2.Y = line1.Point1.Y + (way ? dy : 0); } else if (abs (dy) >= abs (dx) && !x_is_long) { line1.Point2.X = line1.Point1.X + (way ? dx : 0); line1.Point2.Y = line1.Point1.Y + (way ? SGN (dy) * abs (dx) : dy - SGN (dy) * abs (dx)); } else if (x_is_long) { /* we've changed which axis is long, so only do one line */ line1.Point2.X = line1.Point1.X + dx; line1.Point2.Y = line1.Point1.Y + (way ? SGN (dy) * abs (dx) : 0); two_lines = false; } else { /* we've changed which axis is long, so only do one line */ line1.Point2.Y = line1.Point1.Y + dy; line1.Point2.X = line1.Point1.X + (way ? SGN (dx) * abs (dy) : 0); two_lines = false; } line2.Point1.X = line1.Point2.X; line2.Point1.Y = line1.Point2.Y; if (!two_lines) { line2.Point2.Y = line1.Point2.Y; line2.Point2.X = line1.Point2.X; } else { line2.Point2.X = line1.Point1.X + dx; line2.Point2.Y = line1.Point1.Y + dy; } SetLineBoundingBox (&line1); SetLineBoundingBox (&line2); last2 = length2; if (setjmp (info.env) == 0) { info.line = &line1; r_search (PCB->Data->via_tree, &line1.BoundingBox, NULL, drcVia_callback, &info); r_search (PCB->Data->pin_tree, &line1.BoundingBox, NULL, drcVia_callback, &info); if (info.bottom_side || info.top_side) r_search (PCB->Data->pad_tree, &line1.BoundingBox, NULL, drcPad_callback, &info); if (two_lines) { info.line = &line2; r_search (PCB->Data->via_tree, &line2.BoundingBox, NULL, drcVia_callback, &info); r_search (PCB->Data->pin_tree, &line2.BoundingBox, NULL, drcVia_callback, &info); if (info.bottom_side || info.top_side) r_search (PCB->Data->pad_tree, &line2.BoundingBox, NULL, drcPad_callback, &info); } GROUP_LOOP (PCB->Data, group); { info.line = &line1; r_search (layer->line_tree, &line1.BoundingBox, NULL, drcLine_callback, &info); r_search (layer->arc_tree, &line1.BoundingBox, NULL, drcArc_callback, &info); if (two_lines) { info.line = &line2; r_search (layer->line_tree, &line2.BoundingBox, NULL, drcLine_callback, &info); r_search (layer->arc_tree, &line2.BoundingBox, NULL, drcArc_callback, &info); } } END_LOOP; /* no intersector! */ blocker = false; f2 += s2; len = (line2.Point2.X - line1.Point1.X); len *= len; len += (double) (line2.Point2.Y - line1.Point1.Y) * (line2.Point2.Y - line1.Point1.Y); if (len > best) { best = len; ans.X = line2.Point2.X; ans.Y = line2.Point2.Y; } #if 0 if (f2 > 1.0) f2 = 0.5; #endif } else { /* bumped into something, back off */ f2 -= s2; } s2 *= 0.5; length2 = MIN (f2 * temp2, temp2); } if (!blocker && ((x_is_long && line2.Point2.X - line1.Point1.X == dx) || (!x_is_long && line2.Point2.Y - line1.Point1.Y == dy))) f += s; else f -= s; s *= 0.5; length = MIN (f * temp, temp); } end->X = ans.X; end->Y = ans.Y; return best; } void EnforceLineDRC (void) { PointType r45, rs; bool shift; double r1, r2; /* Silence a bogus compiler warning by storing this in a variable */ int layer_idx = INDEXOFCURRENT; if ( gui->mod1_is_pressed() || gui->control_is_pressed () || PCB->RatDraw || layer_idx >= max_copper_layer) return; rs.X = r45.X = Crosshair.X; rs.Y = r45.Y = Crosshair.Y; /* first try starting straight */ r1 = drc_lines (&rs, false); /* then try starting at 45 */ r2 = drc_lines (&r45, true); shift = gui->shift_is_pressed (); if (XOR (r1 > r2, shift)) { if (PCB->Clipping) PCB->Clipping = shift ? 2 : 1; Crosshair.X = rs.X; Crosshair.Y = rs.Y; } else { if (PCB->Clipping) PCB->Clipping = shift ? 1 : 2; Crosshair.X = r45.X; Crosshair.Y = r45.Y; } } pcb-4.2.2/src/object_list.c0000664000076400007640000004201713604156111012454 00000000000000/*! * \file src/object_list.c * * \brief object_list core code * * See src/object_list.h for details. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2018 Charles Parker * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include #include #include //#include "global.h" #if defined(DEBUG_OBJECT_LIST) //&& DEBUG > 0 #define DBG_MSG(fmt, args...) fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt, \ __FILE__, __LINE__, __func__, ##args) #else #define DBG_MSG(fmt, args...) /* Don't do anything in release builds */ #endif #include "object_list.h" static void * object_list_position_pointer(object_list * list, int n); /*! * \brief Create a new object list with n items of size item_size. */ object_list * object_list_new (int n, unsigned item_size) { object_list * list = (object_list*) malloc(sizeof(object_list)); list->item_size = item_size; list->size = n; list->count = 0; /* can I find a way to do this with expand? */ list->items = malloc(n*sizeof(void*)); memset(list->items, 0, list->size*sizeof(void*)); list->data = malloc(n*item_size); list->ops = NULL; return list; } /*! * \brief Copy constructor, copies data too. */ object_list * object_list_duplicate (object_list * list) { object_list * new_list; int i; /* can't duplicate a null pointer*/ if (!list) return 0; new_list = object_list_new(list->size, list->item_size); for (i=0; i< list->count; i++) object_list_append(new_list, object_list_get_item(list, i)); return new_list; } /*! * \brief Delete an object list. */ void object_list_delete (object_list * list) { object_list_clear(list); free(list->items); free(list->data); free(list); } /*! * \brief Delete the data in an object list. */ int object_list_clear (object_list * list) { int i=0; DBG_MSG("Clearing list\n"); if (list->ops && list->ops->clear_object){ DBG_MSG("Clearing with clear operation object\n"); /* If there's a ops structure with a clear function, use it */ for(i=0; i < list->count; i++){ list->ops->clear_object(object_list_get_item(list, i)); } } else { DBG_MSG("Clearing with memset\n"); /* By default, just use memset to clear the item memory. */ memset(list->data, 0, list->size*list->item_size); } memset(list->items, 0, list->size*sizeof(void*)); list->count = 0; return 0; /* success */ } /*! * \brief Make the object list bigger by n items. */ int object_list_expand (object_list * list, int n) { void * new_data = realloc(list->data, (list->size + n)*list->item_size); void ** new_items = realloc(list->items, (list->size + n)*sizeof(void*)); int i=0; DBG_MSG("Expanding list by %d\n", n); if (new_data) list->data = new_data; else printf("[object list] Could not reallocate data memory!\n"); if (new_items) list->items = new_items; else printf("[object list] Could not reallocate item vector memory!\n"); list->size += n; for (i=0; i < list->size; i++) { if (i < list->count) list->items[i] = object_list_position_pointer(list, i); else list->items[i] = 0; } return 0; /* success */ } /*! * \brief Print the list information. */ void object_list_describe (object_list * list) { printf("object list at %p has %d / %d items of size %d bytes\n", list, list->count, list->size, list->item_size); } /*! * \brief Insert an object into the list at position n. */ int object_list_insert (object_list * list, int n, void * item) { void * nptr, * tmp; int nItemsToMove, result; if(n > list->count) return -1; // must be contiguous DBG_MSG("Inserting object at position %d\n", n); /* make sure we have enough room in the list for the new item */ if (list->count == list->size){ result = object_list_expand(list, 1); if (result < 0) { printf("Failed to expand list!\n"); return -1; } } /* move the items to make room for the new one */ nItemsToMove = list->count - n; nptr = object_list_position_pointer(list, n); if (nItemsToMove > 0) { /* copying forward, must use a temp */ DBG_MSG("Need to move %d objects\n", nItemsToMove); tmp = malloc(list->item_size*nItemsToMove); memcpy(tmp, nptr, list->item_size*nItemsToMove); memcpy(nptr+list->item_size, tmp, list->item_size*nItemsToMove); free(tmp); } /* copy the data into the list */ if (list->ops && list->ops->copy_object){ DBG_MSG("Copying with copy operation object\n"); list->ops->copy_object(nptr, item); } else { DBG_MSG("Copying with memcpy\n"); memcpy(nptr, item, list->item_size); } /* Update the pointer list */ list->items[list->count] = object_list_position_pointer(list, list->count); /* increment the list count */ list->count++; return 0; /* success */ } /*! * \brief Remove the object at position n from the list. */ int object_list_remove(object_list * list, int n) { int nItemsToMove; void * nptr, *temp; if(n >= list->count) return -1; // object not in list /* move all items after the specified position up one position */ nItemsToMove = list->count - n - 1; nptr = object_list_get_item(list, n); if (list->ops && list->ops->clear_object){ DBG_MSG("Clearing with clear operation object\n"); list->ops->clear_object(nptr); } /* no point in a memcpy condition since we're about to overwrite it anyway */ /* Copying to an intermediate location appears to be necessary for 32-bit * platforms. * * TODO: Some profiling should be done to see if it's faster to do the * malloc/free move, or to execute a for loop an move one item at a * time, which would not require a memory allocation. */ temp = malloc(list->item_size*nItemsToMove); memcpy(temp, nptr+list->item_size, list->item_size*nItemsToMove); memcpy(nptr, temp, list->item_size*nItemsToMove); free(temp); /* decrement the list count */ list->count--; /* Update the pointer list */ list->items[list->count] = 0; return 0; /* success */ } /*! * \brief Add an objet to the end of the list. */ int object_list_append (object_list * list, void * item) { DBG_MSG("Appending to list... item %d\n", list->count); return object_list_insert (list, list->count, item); } /*! * \brief Get a pointer to the object at position n in the list. */ /* would be nice to allow for negative indexing */ void * object_list_get_item (object_list * list, int n) { if (n >= list->count) return 0; /* not a valid item */ return object_list_position_pointer (list, n); } static void * object_list_position_pointer (object_list * list, int n) { if (n >= list->size) return 0; /* position not in list */ return list->data + list->item_size*n; } /*! * \brief Search the list for something equal to item. * * \note This returns the first match. */ void * object_list_find_item (object_list * list, void * item) { void * list_item; int i; /* We have to have a compare operator to do the testing. * */ if (list->ops == 0) return 0; if (list->ops->compare_objects == 0) return 0; for (i=0; i < list->count; i++) { list_item = object_list_get_item(list, i); if (list->ops->compare_objects(item, list_item) == 0) return list_item; } /* Item not in the list */ return 0; } /* ****************************************************************************** Tests ****************************************************************************** */ #ifdef PCB_UNIT_TEST #include void object_list_register_tests(void) { g_test_add_func("/object-list/test", object_list_test); } typedef struct somestruct { char string[16]; int n; } somestruct; void print_somestruct(somestruct * s) { if(s > 0) printf("%d, %s\n", s->n, s->string); else printf("(null)\n"); } void copy_somestruct(void * a, void * b) { somestruct *aa = (somestruct*)a, *bb = (somestruct*)b; memcpy(aa->string, bb->string, 16); aa->n = bb->n; } void clear_somestruct(void * a) { somestruct *aa = (somestruct*)a; memset(aa->string, 0, 16); aa->n = 0; } int compare_somestructs(void *a, void *b) { somestruct *aa = (somestruct*)a, *bb = (somestruct*)b; if(strncmp(aa->string, bb->string, 16) != 0) return -1; if(aa->n != bb->n) return 1; return 0; } object_operations somestruct_opts = { .copy_object = ©_somestruct, .clear_object = &clear_somestruct, .compare_objects = &compare_somestructs }; /* * check_item is used to validate that a particular item in the list matches * the data of the original item. As a side-effect it also tests * object_list_get_item. * * Note that this is a define rather than a function so that failures are * easier to locate. * */ #define check_item(l, item, n) \ g_assert_cmpint(\ compare_somestructs(&item, object_list_get_item(l, n)), \ ==, 0); \ g_assert_cmpint(\ (gint64) object_list_get_item(l, n), ==, (gint64) l->items[n]); void object_list_test(void) { int ss_size = sizeof(somestruct); somestruct a={"A", 1}, b={"B", 2}, c={"C", 3}, d={"D", 4}, e={"E", 5}, f={"F", 6}; somestruct x={"X", 24}, y={"Y", 25}, z={"Z", 26}; somestruct * p; object_list *list, *dup_list; /* * First test our operations to make sure they work as advertised. */ /* test clearing */ clear_somestruct(&z); g_assert_cmpint(z.n, ==, 0); g_assert_cmpint(strlen(z.string), ==, 0); /* test copying */ copy_somestruct(&z, &y); g_assert_cmpint(z.n, ==, y.n); g_assert_cmpint(strncmp(z.string, y.string, 16), ==, 0); /* test comparing */ /* should be equal by previous test */ g_assert_cmpint(compare_somestructs(&y, &z), ==, 0); /* should be unequal */ g_assert_cmpint(compare_somestructs(&x, &z), !=, 0); /* * Okay, the operations are good to go. Now onto the object_list stuff. */ list = object_list_new(2, ss_size); g_assert_cmpint(list->size, ==, 2); g_assert_cmpint(list->count, ==, 0); g_assert_cmpint(list->item_size, ==, sizeof(somestruct)); /* 0: (null), 1: (null) */ /* * Duplicate a null pointer */ g_assert_cmpint((gint64) object_list_duplicate(0), ==, 0); /* * Duplicating an empty list */ dup_list = object_list_duplicate(list); g_assert_cmpint(dup_list->size, ==, 2); g_assert_cmpint(dup_list->count, ==, 0); g_assert_cmpint(dup_list->item_size, ==, sizeof(somestruct)); /* * Delete an empty list */ object_list_delete(dup_list); /* * Insertion tests */ /* Appending object 'c' to list */ object_list_append(list, &c); /* 0: c, 1: (null) */ check_item(list, c, 0); /* Keeping this long form as a reminder of how it's done */ //g_assert_cmpmem(&c, ss_size, object_list_get_item(list, 0), ss_size); g_assert_cmpint(list->size, ==, 2); g_assert_cmpint(list->count, ==, 1); /* Inserting object 'a' at position 0 (initial position) */ object_list_insert(list, 0, &a); /* 0: a, 1: c */ check_item(list, a, 0); check_item(list, c, 1); g_assert_cmpint(list->size, ==, 2); g_assert_cmpint(list->count, ==, 2); /* Inserting object 'd' at position 2 (append position) */ object_list_insert(list, 2, &d); /* 0: a, 1: c, 2: d */ check_item(list, a, 0); check_item(list, c, 1); check_item(list, d, 2); g_assert_cmpint(list->size, ==, 3); g_assert_cmpint(list->count, ==, 3); /* Inserting object 'b' at position 1 (middle position) */ object_list_insert(list, 1, &b); /* 0: a, 1: b, 2: c, 3: d */ check_item(list, a, 0); check_item(list, b, 1); check_item(list, c, 2); check_item(list, d, 3); g_assert_cmpint(list->size, ==, 4); g_assert_cmpint(list->count, ==, 4); /* Inserting object 'f' at position 5 (past list, fails) */ object_list_insert(list, 5, &f); /* 0: a, 1: b, 2: c, 3: d */ check_item(list, a, 0); check_item(list, b, 1); check_item(list, c, 2); check_item(list, d, 3); g_assert_cmpint(list->size, ==, 4); g_assert_cmpint(list->count, ==, 4); /* Appending object 'e' and expanding */ object_list_append(list, &e); /* 0: a, 1: b, 2: c, 3: d, 4: e*/ check_item(list, a, 0); check_item(list, b, 1); check_item(list, c, 2); check_item(list, d, 3); check_item(list, e, 4); g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 5); /* * Check that find item returns zero, since there are no object operations * yet. */ g_assert_cmpint((gint64) object_list_find_item(list, &c), ==, 0); /* * Duplicate a list with stuff in it */ dup_list = object_list_duplicate(list); /* 0: a, 1: b, 2: c, 3: d, 4: e*/ check_item(dup_list, a, 0); check_item(dup_list, b, 1); check_item(dup_list, c, 2); check_item(dup_list, d, 3); check_item(dup_list, e, 4); g_assert_cmpint(dup_list->size, ==, 5); g_assert_cmpint(dup_list->count, ==, 5); /* * Delete a list with stuff in it */ object_list_delete(dup_list); /* * Removal tests */ /* Removing object at position 0 (initial position) */ object_list_remove(list, 0); /* 0: b, 1: c, 2: d, 3: e, 4: (null) */ check_item(list, b, 0); check_item(list, c, 1); check_item(list, d, 2); check_item(list, e, 3); g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 4); /* Removing object at position 1 (middle position) */ object_list_remove(list, 1); /* 0: b, 1: d, 2: e, 3: (null), 4: (null) */ check_item(list, b, 0); check_item(list, d, 1); check_item(list, e, 2); g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 3); /* Removing object at position 2 (final position) */ object_list_remove(list, 2); /* 0: b, 1: d, 2: (null), 3: (null), 4: (null) */ check_item(list, b, 0); check_item(list, d, 1); g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 2); /* Removing object at position 2 (no item) */ object_list_remove(list, 2); /* 0: b, 1: d, 2: (null), 3: (null), 4: (null) */ check_item(list, b, 0); check_item(list, d, 1); g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 2); /* Clearing list */ object_list_clear(list); /* 0: (null), 1: (null), 2: (null), 3: (null), 4: (null) */ g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 0); /* * Now do these things with the object operations instead of memcopy */ list->ops = &somestruct_opts; /* test use of copy_object */ object_list_append(list, &c); object_list_insert(list, 0, &a); object_list_insert(list, 1, &b); /* 0: a, 1: b, 2: c, 3: (null), 4: (null) */ check_item(list, a, 0); check_item(list, b, 1); check_item(list, c, 2); g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 3); /* test use of clear_object */ /* To do this properly, I would really need to have a pointer to allocated * memory in somestruct, which the clear_object function could free. I'd * then have to find a way to test whether or not that memory still * belonged to me. */ object_list_remove(list, 1); /* 0: a, 1: c, 2: (null), 3: (null), 4: (null) */ check_item(list, a, 0); check_item(list, c, 1); g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 2); /* * Test object_list_find_item */ /* Make the list a little larger. */ object_list_append(list, &e); /* Include a duplicate in the list (we'll never find it). */ object_list_append(list, &c); /* To test finding the last object, last object must be unique */ object_list_append(list, &f); /* 0: a, 1: c, 2: e, 3: c, 4: f */ /* Find the first item */ p = object_list_find_item(list, &a); g_assert_cmpint (compare_somestructs (p, &a), ==, 0); g_assert_cmpint ((gint64) p, ==, (gint64) list->items[0]); /* Find a middle item */ p = object_list_find_item(list, &c); g_assert_cmpint (compare_somestructs (p, &c), ==, 0); g_assert_cmpint ((gint64) p, ==, (gint64) list->items[1]); /* Find the last item */ p = object_list_find_item(list, &f); g_assert_cmpint (compare_somestructs (p, &f), ==, 0); g_assert_cmpint ((gint64) p, ==, (gint64) list->items[4]); /* Find an item not in the list */ p = object_list_find_item(list, &d); g_assert_cmpint ((gint64) p, ==, 0); /* Clearing list */ /* See earlier comment. The same applies here. */ object_list_clear(list); /* 0: (null), 1: (null), 2: (null), 3: (null), 4: (null) */ g_assert_cmpint(list->size, ==, 5); g_assert_cmpint(list->count, ==, 0); /* Deleting list */ /* See earlier comment. The same applies here. */ object_list_delete(list); } #endif /* PCB_UNIT_TEST */ pcb-4.2.2/src/edif.c0000664000076400007640000110736413434562743011107 00000000000000 /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton implementation for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* Substitute the variable and function names. */ #define yyparse edifparse #define yylex ediflex #define yyerror ediferror #define yylval ediflval #define yychar edifchar #define yydebug edifdebug #define yynerrs edifnerrs /* Copy the first part of user declarations. */ /* Line 189 of yacc.c */ #line 1 "edif.y" /* * PCB Edif parser based heavily on: * * Header: edif.y,v 1.18 87/12/07 19:59:49 roger Locked */ /************************************************************************ * * * edif.y * * * * EDIF 2.0.0 parser, Level 0 * * * * You are free to copy, distribute, use it, abuse it, make it * * write bad tracks all over the disk ... or anything else. * * * * Your friendly neighborhood Rogue Monster - roger@mips.com * * * ************************************************************************/ #include /* for malloc, free, atoi */ #include /* for strcpy */ #include #include #include "global.h" #include "data.h" /* from mymem.h, not include because of the malloc junk */ LibraryMenuType * GetLibraryMenuMemory (LibraryType *); LibraryEntryType * GetLibraryEntryMemory (LibraryMenuType *); /* * Local definitions. */ #define IDENT_LENGTH 255 #define Malloc(s) malloc(s) #define Free(p) free(p) #define Getc(s) getc(s) #define Ungetc(c) ungetc(c,Input) typedef struct _str_pair { char* str1; char* str2; struct _str_pair* next; } str_pair; typedef struct _pair_list { char* name; str_pair* list; } pair_list; str_pair* new_str_pair(char* s1, char* s2) { str_pair* ps = (str_pair *)malloc(sizeof(str_pair)); ps->str1 = s1; ps->str2 = s2; ps->next = NULL; return ps; } pair_list* new_pair_list(str_pair* ps) { pair_list* pl = (pair_list *)malloc(sizeof(pair_list)); pl->list = ps; pl->name = NULL; return pl; } void str_pair_free(str_pair* ps) { str_pair* node; while ( ps ) { free(ps->str1); free(ps->str2); node = ps; ps = ps->next; free(node); } } void pair_list_free(pair_list* pl) { str_pair_free(pl->list); free(pl->name); free(pl); } void define_pcb_net(str_pair* name, pair_list* nodes) { int tl; str_pair* done_node; str_pair* node; char* buf; char* p; LibraryEntryType *entry; LibraryMenuType *menu = GetLibraryMenuMemory (&PCB->NetlistLib); if ( !name->str1 ) { /* no net name given, stop now */ /* if renamed str2 also exists and must be freed */ if ( name->str2 ) free(name->str2); free(name); pair_list_free(nodes); return; } menu->Name = strdup (name->str1); free(name->str1); /* if renamed str2 also exists and must be freed */ if ( name->str2 ) free(name->str2); free(name); buf = (char *)malloc(256); if ( !buf ) { /* no memory */ pair_list_free(nodes); return; } node = nodes->list; free(nodes->name); free(nodes); while ( node ) { /* check for node with no instance */ if ( !node->str1 ) { /* toss it and move on */ free(node->str2); done_node = node; node = node->next; free(done_node); continue; } tl = strlen(node->str1) + strlen(node->str2); if ( tl + 3 > 256 ) { free(buf); buf = (char *)malloc(tl+3); if ( !buf ) { /* no memory */ str_pair_free(node); return; } } strcpy(buf,node->str1); /* make all upper case, because of PCB funky behaviour */ p=buf; while ( *p ) { *p = toupper( (int) *p); p++; } /* add dash separating designator from node */ *(buf+strlen(node->str1)) = '-'; /* check for the edif number prefix */ if ( node->str2[0] == '&' ) { /* skip number prefix */ strcpy(buf+strlen(node->str1)+1,node->str2 +1); } else { strcpy(buf+strlen(node->str1)+1,node->str2); } /* free the strings */ free(node->str1); free(node->str2); entry = GetLibraryEntryMemory (menu); entry->ListEntry = strdup(buf); done_node = node; node = node->next; free(done_node); } } /* forward function declarations */ static int yylex(void); static void yyerror(const char *); static void PopC(void); /* Line 189 of yacc.c */ #line 272 "edif.c" /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { EDIF_TOK_IDENT = 258, EDIF_TOK_INT = 259, EDIF_TOK_KEYWORD = 260, EDIF_TOK_STR = 261, EDIF_TOK_ANGLE = 262, EDIF_TOK_BEHAVIOR = 263, EDIF_TOK_CALCULATED = 264, EDIF_TOK_CAPACITANCE = 265, EDIF_TOK_CENTERCENTER = 266, EDIF_TOK_CENTERLEFT = 267, EDIF_TOK_CENTERRIGHT = 268, EDIF_TOK_CHARGE = 269, EDIF_TOK_CONDUCTANCE = 270, EDIF_TOK_CURRENT = 271, EDIF_TOK_DISTANCE = 272, EDIF_TOK_DOCUMENT = 273, EDIF_TOK_ENERGY = 274, EDIF_TOK_EXTEND = 275, EDIF_TOK_FLUX = 276, EDIF_TOK_FREQUENCY = 277, EDIF_TOK_GENERIC = 278, EDIF_TOK_GRAPHIC = 279, EDIF_TOK_INDUCTANCE = 280, EDIF_TOK_INOUT = 281, EDIF_TOK_INPUT = 282, EDIF_TOK_LOGICMODEL = 283, EDIF_TOK_LOWERCENTER = 284, EDIF_TOK_LOWERLEFT = 285, EDIF_TOK_LOWERRIGHT = 286, EDIF_TOK_MASKLAYOUT = 287, EDIF_TOK_MASS = 288, EDIF_TOK_MEASURED = 289, EDIF_TOK_MX = 290, EDIF_TOK_MXR90 = 291, EDIF_TOK_MY = 292, EDIF_TOK_MYR90 = 293, EDIF_TOK_NETLIST = 294, EDIF_TOK_OUTPUT = 295, EDIF_TOK_PCBLAYOUT = 296, EDIF_TOK_POWER = 297, EDIF_TOK_R0 = 298, EDIF_TOK_R180 = 299, EDIF_TOK_R270 = 300, EDIF_TOK_R90 = 301, EDIF_TOK_REQUIRED = 302, EDIF_TOK_RESISTANCE = 303, EDIF_TOK_RIPPER = 304, EDIF_TOK_ROUND = 305, EDIF_TOK_SCHEMATIC = 306, EDIF_TOK_STRANGER = 307, EDIF_TOK_SYMBOLIC = 308, EDIF_TOK_TEMPERATURE = 309, EDIF_TOK_TIE = 310, EDIF_TOK_TIME = 311, EDIF_TOK_TRUNCATE = 312, EDIF_TOK_UPPERCENTER = 313, EDIF_TOK_UPPERLEFT = 314, EDIF_TOK_UPPERRIGHT = 315, EDIF_TOK_VOLTAGE = 316, EDIF_TOK_ACLOAD = 317, EDIF_TOK_AFTER = 318, EDIF_TOK_ANNOTATE = 319, EDIF_TOK_APPLY = 320, EDIF_TOK_ARC = 321, EDIF_TOK_ARRAY = 322, EDIF_TOK_ARRAYMACRO = 323, EDIF_TOK_ARRAYRELATEDINFO = 324, EDIF_TOK_ARRAYSITE = 325, EDIF_TOK_ATLEAST = 326, EDIF_TOK_ATMOST = 327, EDIF_TOK_AUTHOR = 328, EDIF_TOK_BASEARRAY = 329, EDIF_TOK_BECOMES = 330, EDIF_TOK_BETWEEN = 331, EDIF_TOK_BOOLEAN = 332, EDIF_TOK_BOOLEANDISPLAY = 333, EDIF_TOK_BOOLEANMAP = 334, EDIF_TOK_BORDERPATTERN = 335, EDIF_TOK_BORDERWIDTH = 336, EDIF_TOK_BOUNDINGBOX = 337, EDIF_TOK_CELL = 338, EDIF_TOK_CELLREF = 339, EDIF_TOK_CELLTYPE = 340, EDIF_TOK_CHANGE = 341, EDIF_TOK_CIRCLE = 342, EDIF_TOK_COLOR = 343, EDIF_TOK_COMMENT = 344, EDIF_TOK_COMMENTGRAPHICS = 345, EDIF_TOK_COMPOUND = 346, EDIF_TOK_CONNECTLOCATION = 347, EDIF_TOK_CONTENTS = 348, EDIF_TOK_CORNERTYPE = 349, EDIF_TOK_CRITICALITY = 350, EDIF_TOK_CURRENTMAP = 351, EDIF_TOK_CURVE = 352, EDIF_TOK_CYCLE = 353, EDIF_TOK_DATAORIGIN = 354, EDIF_TOK_DCFANINLOAD = 355, EDIF_TOK_DCFANOUTLOAD = 356, EDIF_TOK_DCMAXFANIN = 357, EDIF_TOK_DCMAXFANOUT = 358, EDIF_TOK_DELAY = 359, EDIF_TOK_DELTA = 360, EDIF_TOK_DERIVATION = 361, EDIF_TOK_DESIGN = 362, EDIF_TOK_DESIGNATOR = 363, EDIF_TOK_DIFFERENCE = 364, EDIF_TOK_DIRECTION = 365, EDIF_TOK_DISPLAY = 366, EDIF_TOK_DOMINATES = 367, EDIF_TOK_DOT = 368, EDIF_TOK_DURATION = 369, EDIF_TOK_E = 370, EDIF_TOK_EDIF = 371, EDIF_TOK_EDIFLEVEL = 372, EDIF_TOK_EDIFVERSION = 373, EDIF_TOK_ENCLOSUREDISTANCE = 374, EDIF_TOK_ENDTYPE = 375, EDIF_TOK_ENTRY = 376, EDIF_TOK_EVENT = 377, EDIF_TOK_EXACTLY = 378, EDIF_TOK_EXTERNAL = 379, EDIF_TOK_FABRICATE = 380, EDIF_TOK_FALSE = 381, EDIF_TOK_FIGURE = 382, EDIF_TOK_FIGUREAREA = 383, EDIF_TOK_FIGUREGROUP = 384, EDIF_TOK_FIGUREGROUPOBJECT = 385, EDIF_TOK_FIGUREGROUPOVERRIDE = 386, EDIF_TOK_FIGUREGROUPREF = 387, EDIF_TOK_FIGUREPERIMETER = 388, EDIF_TOK_FIGUREWIDTH = 389, EDIF_TOK_FILLPATTERN = 390, EDIF_TOK_FOLLOW = 391, EDIF_TOK_FORBIDDENEVENT = 392, EDIF_TOK_GLOBALPORTREF = 393, EDIF_TOK_GREATERTHAN = 394, EDIF_TOK_GRIDMAP = 395, EDIF_TOK_IGNORE = 396, EDIF_TOK_INCLUDEFIGUREGROUP = 397, EDIF_TOK_INITIAL = 398, EDIF_TOK_INSTANCE = 399, EDIF_TOK_INSTANCEBACKANNOTATE = 400, EDIF_TOK_INSTANCEGROUP = 401, EDIF_TOK_INSTANCEMAP = 402, EDIF_TOK_INSTANCEREF = 403, EDIF_TOK_INTEGER = 404, EDIF_TOK_INTEGERDISPLAY = 405, EDIF_TOK_INTERFACE = 406, EDIF_TOK_INTERFIGUREGROUPSPACING = 407, EDIF_TOK_INTERSECTION = 408, EDIF_TOK_INTRAFIGUREGROUPSPACING = 409, EDIF_TOK_INVERSE = 410, EDIF_TOK_ISOLATED = 411, EDIF_TOK_JOINED = 412, EDIF_TOK_JUSTIFY = 413, EDIF_TOK_KEYWORDDISPLAY = 414, EDIF_TOK_KEYWORDLEVEL = 415, EDIF_TOK_KEYWORDMAP = 416, EDIF_TOK_LESSTHAN = 417, EDIF_TOK_LIBRARY = 418, EDIF_TOK_LIBRARYREF = 419, EDIF_TOK_LISTOFNETS = 420, EDIF_TOK_LISTOFPORTS = 421, EDIF_TOK_LOADDELAY = 422, EDIF_TOK_LOGICASSIGN = 423, EDIF_TOK_LOGICINPUT = 424, EDIF_TOK_LOGICLIST = 425, EDIF_TOK_LOGICMAPINPUT = 426, EDIF_TOK_LOGICMAPOUTPUT = 427, EDIF_TOK_LOGICONEOF = 428, EDIF_TOK_LOGICOUTPUT = 429, EDIF_TOK_LOGICPORT = 430, EDIF_TOK_LOGICREF = 431, EDIF_TOK_LOGICVALUE = 432, EDIF_TOK_LOGICWAVEFORM = 433, EDIF_TOK_MAINTAIN = 434, EDIF_TOK_MATCH = 435, EDIF_TOK_MEMBER = 436, EDIF_TOK_MINOMAX = 437, EDIF_TOK_MINOMAXDISPLAY = 438, EDIF_TOK_MNM = 439, EDIF_TOK_MULTIPLEVALUESET = 440, EDIF_TOK_MUSTJOIN = 441, EDIF_TOK_NAME = 442, EDIF_TOK_NET = 443, EDIF_TOK_NETBACKANNOTATE = 444, EDIF_TOK_NETBUNDLE = 445, EDIF_TOK_NETDELAY = 446, EDIF_TOK_NETGROUP = 447, EDIF_TOK_NETMAP = 448, EDIF_TOK_NETREF = 449, EDIF_TOK_NOCHANGE = 450, EDIF_TOK_NONPERMUTABLE = 451, EDIF_TOK_NOTALLOWED = 452, EDIF_TOK_NOTCHSPACING = 453, EDIF_TOK_NUMBER = 454, EDIF_TOK_NUMBERDEFINITION = 455, EDIF_TOK_NUMBERDISPLAY = 456, EDIF_TOK_OFFPAGECONNECTOR = 457, EDIF_TOK_OFFSETEVENT = 458, EDIF_TOK_OPENSHAPE = 459, EDIF_TOK_ORIENTATION = 460, EDIF_TOK_ORIGIN = 461, EDIF_TOK_OVERHANGDISTANCE = 462, EDIF_TOK_OVERLAPDISTANCE = 463, EDIF_TOK_OVERSIZE = 464, EDIF_TOK_OWNER = 465, EDIF_TOK_PAGE = 466, EDIF_TOK_PAGESIZE = 467, EDIF_TOK_PARAMETER = 468, EDIF_TOK_PARAMETERASSIGN = 469, EDIF_TOK_PARAMETERDISPLAY = 470, EDIF_TOK_PATH = 471, EDIF_TOK_PATHDELAY = 472, EDIF_TOK_PATHWIDTH = 473, EDIF_TOK_PERMUTABLE = 474, EDIF_TOK_PHYSICALDESIGNRULE = 475, EDIF_TOK_PLUG = 476, EDIF_TOK_POINT = 477, EDIF_TOK_POINTDISPLAY = 478, EDIF_TOK_POINTLIST = 479, EDIF_TOK_POLYGON = 480, EDIF_TOK_PORT = 481, EDIF_TOK_PORTBACKANNOTATE = 482, EDIF_TOK_PORTBUNDLE = 483, EDIF_TOK_PORTDELAY = 484, EDIF_TOK_PORTGROUP = 485, EDIF_TOK_PORTIMPLEMENTATION = 486, EDIF_TOK_PORTINSTANCE = 487, EDIF_TOK_PORTLIST = 488, EDIF_TOK_PORTLISTALIAS = 489, EDIF_TOK_PORTMAP = 490, EDIF_TOK_PORTREF = 491, EDIF_TOK_PROGRAM = 492, EDIF_TOK_PROPERTY = 493, EDIF_TOK_PROPERTYDISPLAY = 494, EDIF_TOK_PROTECTIONFRAME = 495, EDIF_TOK_PT = 496, EDIF_TOK_RANGEVECTOR = 497, EDIF_TOK_RECTANGLE = 498, EDIF_TOK_RECTANGLESIZE = 499, EDIF_TOK_RENAME = 500, EDIF_TOK_RESOLVES = 501, EDIF_TOK_SCALE = 502, EDIF_TOK_SCALEX = 503, EDIF_TOK_SCALEY = 504, EDIF_TOK_SECTION = 505, EDIF_TOK_SHAPE = 506, EDIF_TOK_SIMULATE = 507, EDIF_TOK_SIMULATIONINFO = 508, EDIF_TOK_SINGLEVALUESET = 509, EDIF_TOK_SITE = 510, EDIF_TOK_SOCKET = 511, EDIF_TOK_SOCKETSET = 512, EDIF_TOK_STATUS = 513, EDIF_TOK_STEADY = 514, EDIF_TOK_STRING = 515, EDIF_TOK_STRINGDISPLAY = 516, EDIF_TOK_STRONG = 517, EDIF_TOK_SYMBOL = 518, EDIF_TOK_SYMMETRY = 519, EDIF_TOK_TABLE = 520, EDIF_TOK_TABLEDEFAULT = 521, EDIF_TOK_TECHNOLOGY = 522, EDIF_TOK_TEXTHEIGHT = 523, EDIF_TOK_TIMEINTERVAL = 524, EDIF_TOK_TIMESTAMP = 525, EDIF_TOK_TIMING = 526, EDIF_TOK_TRANSFORM = 527, EDIF_TOK_TRANSITION = 528, EDIF_TOK_TRIGGER = 529, EDIF_TOK_TRUE = 530, EDIF_TOK_UNCONSTRAINED = 531, EDIF_TOK_UNDEFINED = 532, EDIF_TOK_UNION = 533, EDIF_TOK_UNIT = 534, EDIF_TOK_UNUSED = 535, EDIF_TOK_USERDATA = 536, EDIF_TOK_VERSION = 537, EDIF_TOK_VIEW = 538, EDIF_TOK_VIEWLIST = 539, EDIF_TOK_VIEWMAP = 540, EDIF_TOK_VIEWREF = 541, EDIF_TOK_VIEWTYPE = 542, EDIF_TOK_VISIBLE = 543, EDIF_TOK_VOLTAGEMAP = 544, EDIF_TOK_WAVEVALUE = 545, EDIF_TOK_WEAK = 546, EDIF_TOK_WEAKJOINED = 547, EDIF_TOK_WHEN = 548, EDIF_TOK_WRITTEN = 549 }; #endif /* Tokens. */ #define EDIF_TOK_IDENT 258 #define EDIF_TOK_INT 259 #define EDIF_TOK_KEYWORD 260 #define EDIF_TOK_STR 261 #define EDIF_TOK_ANGLE 262 #define EDIF_TOK_BEHAVIOR 263 #define EDIF_TOK_CALCULATED 264 #define EDIF_TOK_CAPACITANCE 265 #define EDIF_TOK_CENTERCENTER 266 #define EDIF_TOK_CENTERLEFT 267 #define EDIF_TOK_CENTERRIGHT 268 #define EDIF_TOK_CHARGE 269 #define EDIF_TOK_CONDUCTANCE 270 #define EDIF_TOK_CURRENT 271 #define EDIF_TOK_DISTANCE 272 #define EDIF_TOK_DOCUMENT 273 #define EDIF_TOK_ENERGY 274 #define EDIF_TOK_EXTEND 275 #define EDIF_TOK_FLUX 276 #define EDIF_TOK_FREQUENCY 277 #define EDIF_TOK_GENERIC 278 #define EDIF_TOK_GRAPHIC 279 #define EDIF_TOK_INDUCTANCE 280 #define EDIF_TOK_INOUT 281 #define EDIF_TOK_INPUT 282 #define EDIF_TOK_LOGICMODEL 283 #define EDIF_TOK_LOWERCENTER 284 #define EDIF_TOK_LOWERLEFT 285 #define EDIF_TOK_LOWERRIGHT 286 #define EDIF_TOK_MASKLAYOUT 287 #define EDIF_TOK_MASS 288 #define EDIF_TOK_MEASURED 289 #define EDIF_TOK_MX 290 #define EDIF_TOK_MXR90 291 #define EDIF_TOK_MY 292 #define EDIF_TOK_MYR90 293 #define EDIF_TOK_NETLIST 294 #define EDIF_TOK_OUTPUT 295 #define EDIF_TOK_PCBLAYOUT 296 #define EDIF_TOK_POWER 297 #define EDIF_TOK_R0 298 #define EDIF_TOK_R180 299 #define EDIF_TOK_R270 300 #define EDIF_TOK_R90 301 #define EDIF_TOK_REQUIRED 302 #define EDIF_TOK_RESISTANCE 303 #define EDIF_TOK_RIPPER 304 #define EDIF_TOK_ROUND 305 #define EDIF_TOK_SCHEMATIC 306 #define EDIF_TOK_STRANGER 307 #define EDIF_TOK_SYMBOLIC 308 #define EDIF_TOK_TEMPERATURE 309 #define EDIF_TOK_TIE 310 #define EDIF_TOK_TIME 311 #define EDIF_TOK_TRUNCATE 312 #define EDIF_TOK_UPPERCENTER 313 #define EDIF_TOK_UPPERLEFT 314 #define EDIF_TOK_UPPERRIGHT 315 #define EDIF_TOK_VOLTAGE 316 #define EDIF_TOK_ACLOAD 317 #define EDIF_TOK_AFTER 318 #define EDIF_TOK_ANNOTATE 319 #define EDIF_TOK_APPLY 320 #define EDIF_TOK_ARC 321 #define EDIF_TOK_ARRAY 322 #define EDIF_TOK_ARRAYMACRO 323 #define EDIF_TOK_ARRAYRELATEDINFO 324 #define EDIF_TOK_ARRAYSITE 325 #define EDIF_TOK_ATLEAST 326 #define EDIF_TOK_ATMOST 327 #define EDIF_TOK_AUTHOR 328 #define EDIF_TOK_BASEARRAY 329 #define EDIF_TOK_BECOMES 330 #define EDIF_TOK_BETWEEN 331 #define EDIF_TOK_BOOLEAN 332 #define EDIF_TOK_BOOLEANDISPLAY 333 #define EDIF_TOK_BOOLEANMAP 334 #define EDIF_TOK_BORDERPATTERN 335 #define EDIF_TOK_BORDERWIDTH 336 #define EDIF_TOK_BOUNDINGBOX 337 #define EDIF_TOK_CELL 338 #define EDIF_TOK_CELLREF 339 #define EDIF_TOK_CELLTYPE 340 #define EDIF_TOK_CHANGE 341 #define EDIF_TOK_CIRCLE 342 #define EDIF_TOK_COLOR 343 #define EDIF_TOK_COMMENT 344 #define EDIF_TOK_COMMENTGRAPHICS 345 #define EDIF_TOK_COMPOUND 346 #define EDIF_TOK_CONNECTLOCATION 347 #define EDIF_TOK_CONTENTS 348 #define EDIF_TOK_CORNERTYPE 349 #define EDIF_TOK_CRITICALITY 350 #define EDIF_TOK_CURRENTMAP 351 #define EDIF_TOK_CURVE 352 #define EDIF_TOK_CYCLE 353 #define EDIF_TOK_DATAORIGIN 354 #define EDIF_TOK_DCFANINLOAD 355 #define EDIF_TOK_DCFANOUTLOAD 356 #define EDIF_TOK_DCMAXFANIN 357 #define EDIF_TOK_DCMAXFANOUT 358 #define EDIF_TOK_DELAY 359 #define EDIF_TOK_DELTA 360 #define EDIF_TOK_DERIVATION 361 #define EDIF_TOK_DESIGN 362 #define EDIF_TOK_DESIGNATOR 363 #define EDIF_TOK_DIFFERENCE 364 #define EDIF_TOK_DIRECTION 365 #define EDIF_TOK_DISPLAY 366 #define EDIF_TOK_DOMINATES 367 #define EDIF_TOK_DOT 368 #define EDIF_TOK_DURATION 369 #define EDIF_TOK_E 370 #define EDIF_TOK_EDIF 371 #define EDIF_TOK_EDIFLEVEL 372 #define EDIF_TOK_EDIFVERSION 373 #define EDIF_TOK_ENCLOSUREDISTANCE 374 #define EDIF_TOK_ENDTYPE 375 #define EDIF_TOK_ENTRY 376 #define EDIF_TOK_EVENT 377 #define EDIF_TOK_EXACTLY 378 #define EDIF_TOK_EXTERNAL 379 #define EDIF_TOK_FABRICATE 380 #define EDIF_TOK_FALSE 381 #define EDIF_TOK_FIGURE 382 #define EDIF_TOK_FIGUREAREA 383 #define EDIF_TOK_FIGUREGROUP 384 #define EDIF_TOK_FIGUREGROUPOBJECT 385 #define EDIF_TOK_FIGUREGROUPOVERRIDE 386 #define EDIF_TOK_FIGUREGROUPREF 387 #define EDIF_TOK_FIGUREPERIMETER 388 #define EDIF_TOK_FIGUREWIDTH 389 #define EDIF_TOK_FILLPATTERN 390 #define EDIF_TOK_FOLLOW 391 #define EDIF_TOK_FORBIDDENEVENT 392 #define EDIF_TOK_GLOBALPORTREF 393 #define EDIF_TOK_GREATERTHAN 394 #define EDIF_TOK_GRIDMAP 395 #define EDIF_TOK_IGNORE 396 #define EDIF_TOK_INCLUDEFIGUREGROUP 397 #define EDIF_TOK_INITIAL 398 #define EDIF_TOK_INSTANCE 399 #define EDIF_TOK_INSTANCEBACKANNOTATE 400 #define EDIF_TOK_INSTANCEGROUP 401 #define EDIF_TOK_INSTANCEMAP 402 #define EDIF_TOK_INSTANCEREF 403 #define EDIF_TOK_INTEGER 404 #define EDIF_TOK_INTEGERDISPLAY 405 #define EDIF_TOK_INTERFACE 406 #define EDIF_TOK_INTERFIGUREGROUPSPACING 407 #define EDIF_TOK_INTERSECTION 408 #define EDIF_TOK_INTRAFIGUREGROUPSPACING 409 #define EDIF_TOK_INVERSE 410 #define EDIF_TOK_ISOLATED 411 #define EDIF_TOK_JOINED 412 #define EDIF_TOK_JUSTIFY 413 #define EDIF_TOK_KEYWORDDISPLAY 414 #define EDIF_TOK_KEYWORDLEVEL 415 #define EDIF_TOK_KEYWORDMAP 416 #define EDIF_TOK_LESSTHAN 417 #define EDIF_TOK_LIBRARY 418 #define EDIF_TOK_LIBRARYREF 419 #define EDIF_TOK_LISTOFNETS 420 #define EDIF_TOK_LISTOFPORTS 421 #define EDIF_TOK_LOADDELAY 422 #define EDIF_TOK_LOGICASSIGN 423 #define EDIF_TOK_LOGICINPUT 424 #define EDIF_TOK_LOGICLIST 425 #define EDIF_TOK_LOGICMAPINPUT 426 #define EDIF_TOK_LOGICMAPOUTPUT 427 #define EDIF_TOK_LOGICONEOF 428 #define EDIF_TOK_LOGICOUTPUT 429 #define EDIF_TOK_LOGICPORT 430 #define EDIF_TOK_LOGICREF 431 #define EDIF_TOK_LOGICVALUE 432 #define EDIF_TOK_LOGICWAVEFORM 433 #define EDIF_TOK_MAINTAIN 434 #define EDIF_TOK_MATCH 435 #define EDIF_TOK_MEMBER 436 #define EDIF_TOK_MINOMAX 437 #define EDIF_TOK_MINOMAXDISPLAY 438 #define EDIF_TOK_MNM 439 #define EDIF_TOK_MULTIPLEVALUESET 440 #define EDIF_TOK_MUSTJOIN 441 #define EDIF_TOK_NAME 442 #define EDIF_TOK_NET 443 #define EDIF_TOK_NETBACKANNOTATE 444 #define EDIF_TOK_NETBUNDLE 445 #define EDIF_TOK_NETDELAY 446 #define EDIF_TOK_NETGROUP 447 #define EDIF_TOK_NETMAP 448 #define EDIF_TOK_NETREF 449 #define EDIF_TOK_NOCHANGE 450 #define EDIF_TOK_NONPERMUTABLE 451 #define EDIF_TOK_NOTALLOWED 452 #define EDIF_TOK_NOTCHSPACING 453 #define EDIF_TOK_NUMBER 454 #define EDIF_TOK_NUMBERDEFINITION 455 #define EDIF_TOK_NUMBERDISPLAY 456 #define EDIF_TOK_OFFPAGECONNECTOR 457 #define EDIF_TOK_OFFSETEVENT 458 #define EDIF_TOK_OPENSHAPE 459 #define EDIF_TOK_ORIENTATION 460 #define EDIF_TOK_ORIGIN 461 #define EDIF_TOK_OVERHANGDISTANCE 462 #define EDIF_TOK_OVERLAPDISTANCE 463 #define EDIF_TOK_OVERSIZE 464 #define EDIF_TOK_OWNER 465 #define EDIF_TOK_PAGE 466 #define EDIF_TOK_PAGESIZE 467 #define EDIF_TOK_PARAMETER 468 #define EDIF_TOK_PARAMETERASSIGN 469 #define EDIF_TOK_PARAMETERDISPLAY 470 #define EDIF_TOK_PATH 471 #define EDIF_TOK_PATHDELAY 472 #define EDIF_TOK_PATHWIDTH 473 #define EDIF_TOK_PERMUTABLE 474 #define EDIF_TOK_PHYSICALDESIGNRULE 475 #define EDIF_TOK_PLUG 476 #define EDIF_TOK_POINT 477 #define EDIF_TOK_POINTDISPLAY 478 #define EDIF_TOK_POINTLIST 479 #define EDIF_TOK_POLYGON 480 #define EDIF_TOK_PORT 481 #define EDIF_TOK_PORTBACKANNOTATE 482 #define EDIF_TOK_PORTBUNDLE 483 #define EDIF_TOK_PORTDELAY 484 #define EDIF_TOK_PORTGROUP 485 #define EDIF_TOK_PORTIMPLEMENTATION 486 #define EDIF_TOK_PORTINSTANCE 487 #define EDIF_TOK_PORTLIST 488 #define EDIF_TOK_PORTLISTALIAS 489 #define EDIF_TOK_PORTMAP 490 #define EDIF_TOK_PORTREF 491 #define EDIF_TOK_PROGRAM 492 #define EDIF_TOK_PROPERTY 493 #define EDIF_TOK_PROPERTYDISPLAY 494 #define EDIF_TOK_PROTECTIONFRAME 495 #define EDIF_TOK_PT 496 #define EDIF_TOK_RANGEVECTOR 497 #define EDIF_TOK_RECTANGLE 498 #define EDIF_TOK_RECTANGLESIZE 499 #define EDIF_TOK_RENAME 500 #define EDIF_TOK_RESOLVES 501 #define EDIF_TOK_SCALE 502 #define EDIF_TOK_SCALEX 503 #define EDIF_TOK_SCALEY 504 #define EDIF_TOK_SECTION 505 #define EDIF_TOK_SHAPE 506 #define EDIF_TOK_SIMULATE 507 #define EDIF_TOK_SIMULATIONINFO 508 #define EDIF_TOK_SINGLEVALUESET 509 #define EDIF_TOK_SITE 510 #define EDIF_TOK_SOCKET 511 #define EDIF_TOK_SOCKETSET 512 #define EDIF_TOK_STATUS 513 #define EDIF_TOK_STEADY 514 #define EDIF_TOK_STRING 515 #define EDIF_TOK_STRINGDISPLAY 516 #define EDIF_TOK_STRONG 517 #define EDIF_TOK_SYMBOL 518 #define EDIF_TOK_SYMMETRY 519 #define EDIF_TOK_TABLE 520 #define EDIF_TOK_TABLEDEFAULT 521 #define EDIF_TOK_TECHNOLOGY 522 #define EDIF_TOK_TEXTHEIGHT 523 #define EDIF_TOK_TIMEINTERVAL 524 #define EDIF_TOK_TIMESTAMP 525 #define EDIF_TOK_TIMING 526 #define EDIF_TOK_TRANSFORM 527 #define EDIF_TOK_TRANSITION 528 #define EDIF_TOK_TRIGGER 529 #define EDIF_TOK_TRUE 530 #define EDIF_TOK_UNCONSTRAINED 531 #define EDIF_TOK_UNDEFINED 532 #define EDIF_TOK_UNION 533 #define EDIF_TOK_UNIT 534 #define EDIF_TOK_UNUSED 535 #define EDIF_TOK_USERDATA 536 #define EDIF_TOK_VERSION 537 #define EDIF_TOK_VIEW 538 #define EDIF_TOK_VIEWLIST 539 #define EDIF_TOK_VIEWMAP 540 #define EDIF_TOK_VIEWREF 541 #define EDIF_TOK_VIEWTYPE 542 #define EDIF_TOK_VISIBLE 543 #define EDIF_TOK_VOLTAGEMAP 544 #define EDIF_TOK_WAVEVALUE 545 #define EDIF_TOK_WEAK 546 #define EDIF_TOK_WEAKJOINED 547 #define EDIF_TOK_WHEN 548 #define EDIF_TOK_WRITTEN 549 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 214 of yacc.c */ #line 193 "edif.y" char* s; pair_list* pl; str_pair* ps; /* Line 214 of yacc.c */ #line 904 "edif.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif /* Copy the second part of user declarations. */ /* Line 264 of yacc.c */ #line 916 "edif.c" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 11 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 2619 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 296 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 472 /* YYNRULES -- Number of rules. */ #define YYNRULES 1129 /* YYNRULES -- Number of states. */ #define YYNSTATES 1626 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 549 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint16 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 295, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint16 yyprhs[] = { 0, 0, 3, 5, 13, 14, 17, 20, 23, 26, 29, 32, 34, 38, 44, 48, 50, 52, 56, 58, 61, 64, 67, 70, 73, 77, 79, 81, 85, 87, 90, 93, 96, 99, 105, 111, 112, 114, 118, 122, 124, 126, 128, 131, 134, 138, 142, 146, 150, 153, 157, 159, 161, 163, 168, 170, 172, 174, 176, 180, 181, 184, 187, 190, 194, 196, 199, 203, 205, 207, 213, 217, 221, 226, 228, 231, 234, 237, 240, 243, 246, 248, 253, 254, 256, 258, 262, 264, 266, 268, 273, 275, 277, 279, 280, 282, 284, 290, 291, 294, 300, 304, 305, 308, 312, 313, 316, 319, 322, 325, 328, 331, 334, 338, 342, 343, 346, 349, 352, 355, 358, 361, 364, 367, 370, 373, 376, 379, 382, 385, 388, 391, 394, 398, 399, 401, 405, 407, 409, 411, 415, 417, 419, 423, 427, 428, 431, 434, 439, 440, 442, 447, 448, 450, 454, 456, 458, 462, 464, 466, 470, 472, 474, 478, 480, 482, 486, 488, 490, 494, 495, 498, 502, 504, 506, 508, 513, 515, 518, 521, 524, 527, 531, 533, 535, 537, 541, 542, 545, 548, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584, 588, 590, 592, 595, 598, 602, 604, 606, 608, 615, 617, 619, 620, 622, 623, 625, 626, 628, 632, 633, 636, 640, 642, 645, 649, 656, 658, 660, 663, 666, 670, 672, 674, 676, 682, 684, 686, 688, 690, 692, 694, 696, 697, 699, 701, 705, 707, 709, 711, 713, 715, 718, 721, 725, 731, 733, 736, 739, 742, 745, 750, 753, 757, 759, 762, 765, 768, 771, 774, 777, 780, 783, 786, 789, 792, 795, 798, 800, 802, 806, 808, 810, 812, 816, 818, 821, 824, 827, 830, 833, 836, 839, 842, 845, 848, 851, 854, 859, 860, 862, 866, 868, 870, 873, 876, 879, 882, 885, 888, 891, 894, 897, 903, 905, 907, 910, 913, 915, 917, 919, 921, 923, 929, 931, 933, 936, 939, 945, 947, 949, 952, 955, 961, 966, 968, 970, 972, 974, 977, 980, 984, 986, 989, 993, 994, 997, 1000, 1003, 1006, 1010, 1014, 1019, 1022, 1026, 1028, 1030, 1033, 1038, 1040, 1042, 1045, 1048, 1051, 1054, 1057, 1060, 1063, 1066, 1071, 1072, 1074, 1076, 1080, 1082, 1085, 1088, 1091, 1094, 1098, 1099, 1102, 1106, 1107, 1110, 1113, 1116, 1119, 1121, 1123, 1125, 1127, 1131, 1133, 1136, 1140, 1141, 1144, 1147, 1150, 1154, 1155, 1158, 1161, 1164, 1167, 1170, 1173, 1176, 1179, 1182, 1185, 1188, 1191, 1194, 1197, 1200, 1203, 1210, 1212, 1214, 1217, 1220, 1224, 1226, 1228, 1231, 1234, 1240, 1242, 1244, 1247, 1250, 1254, 1256, 1258, 1261, 1265, 1266, 1269, 1272, 1275, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1301, 1303, 1306, 1310, 1314, 1316, 1319, 1321, 1323, 1327, 1329, 1331, 1337, 1339, 1342, 1345, 1348, 1351, 1355, 1359, 1360, 1363, 1367, 1368, 1371, 1374, 1379, 1381, 1383, 1389, 1391, 1393, 1395, 1397, 1399, 1400, 1402, 1404, 1408, 1410, 1412, 1414, 1417, 1421, 1422, 1425, 1428, 1431, 1435, 1436, 1439, 1443, 1444, 1447, 1449, 1451, 1455, 1456, 1459, 1462, 1466, 1468, 1470, 1472, 1475, 1479, 1481, 1484, 1487, 1490, 1495, 1496, 1498, 1502, 1504, 1507, 1510, 1513, 1516, 1519, 1522, 1525, 1528, 1531, 1534, 1537, 1540, 1543, 1546, 1550, 1551, 1554, 1557, 1560, 1563, 1568, 1570, 1572, 1573, 1575, 1577, 1582, 1584, 1586, 1588, 1590, 1592, 1594, 1599, 1601, 1604, 1608, 1609, 1612, 1615, 1618, 1622, 1624, 1627, 1629, 1631, 1637, 1639, 1641, 1643, 1647, 1648, 1651, 1655, 1656, 1659, 1662, 1665, 1668, 1672, 1674, 1677, 1679, 1681, 1683, 1685, 1687, 1692, 1694, 1697, 1700, 1703, 1706, 1709, 1712, 1715, 1718, 1721, 1725, 1727, 1730, 1733, 1736, 1739, 1744, 1746, 1749, 1752, 1755, 1758, 1761, 1766, 1768, 1771, 1774, 1778, 1779, 1782, 1785, 1789, 1790, 1793, 1796, 1799, 1802, 1804, 1806, 1808, 1810, 1815, 1816, 1818, 1820, 1822, 1825, 1829, 1830, 1833, 1836, 1841, 1843, 1846, 1849, 1855, 1857, 1859, 1862, 1865, 1869, 1870, 1873, 1876, 1879, 1883, 1885, 1888, 1892, 1893, 1896, 1899, 1902, 1906, 1908, 1911, 1914, 1917, 1920, 1925, 1929, 1931, 1934, 1938, 1940, 1942, 1944, 1946, 1948, 1950, 1952, 1954, 1958, 1965, 1967, 1969, 1972, 1975, 1982, 1984, 1986, 1989, 1992, 1998, 2000, 2002, 2006, 2010, 2012, 2015, 2018, 2021, 2024, 2027, 2030, 2033, 2036, 2039, 2043, 2047, 2049, 2052, 2058, 2059, 2061, 2066, 2070, 2072, 2075, 2079, 2081, 2084, 2088, 2092, 2093, 2096, 2099, 2102, 2106, 2107, 2110, 2114, 2115, 2118, 2121, 2124, 2128, 2130, 2133, 2137, 2138, 2141, 2146, 2150, 2152, 2155, 2159, 2161, 2164, 2167, 2170, 2173, 2176, 2179, 2182, 2185, 2188, 2191, 2194, 2197, 2201, 2203, 2206, 2209, 2212, 2215, 2218, 2221, 2224, 2227, 2230, 2235, 2237, 2240, 2243, 2246, 2251, 2253, 2255, 2258, 2261, 2265, 2266, 2269, 2272, 2276, 2278, 2280, 2283, 2286, 2289, 2292, 2295, 2298, 2301, 2304, 2307, 2311, 2313, 2315, 2318, 2321, 2324, 2327, 2330, 2333, 2336, 2339, 2342, 2345, 2348, 2352, 2353, 2356, 2359, 2364, 2368, 2369, 2372, 2375, 2378, 2381, 2383, 2385, 2387, 2389, 2394, 2395, 2397, 2399, 2401, 2406, 2407, 2409, 2413, 2415, 2418, 2423, 2425, 2428, 2431, 2434, 2437, 2439, 2441, 2445, 2446, 2449, 2452, 2455, 2458, 2461, 2464, 2467, 2470, 2473, 2476, 2479, 2481, 2483, 2485, 2487, 2489, 2491, 2495, 2496, 2499, 2502, 2507, 2509, 2512, 2518, 2520, 2522, 2525, 2528, 2533, 2535, 2537, 2539, 2541, 2545, 2546, 2549, 2551, 2557, 2559, 2564, 2569, 2574, 2578, 2580, 2583, 2586, 2589, 2593, 2595, 2598, 2600, 2604, 2606, 2609, 2612, 2615, 2618, 2621, 2625, 2626, 2629, 2632, 2635, 2639, 2640, 2642, 2647, 2648, 2650, 2654, 2655, 2657, 2661, 2663, 2666, 2670, 2671, 2674, 2677, 2680, 2685, 2687, 2689, 2691, 2693, 2696, 2699, 2703, 2707, 2708, 2711, 2714, 2717, 2719, 2722, 2726, 2730, 2731, 2734, 2737, 2740, 2743, 2746, 2749, 2752, 2755, 2758, 2761, 2764, 2767, 2770, 2774, 2775, 2778, 2782, 2783, 2786, 2789, 2794, 2796, 2798, 2800, 2802, 2803, 2805, 2807, 2811, 2813, 2816, 2819, 2822, 2825, 2828, 2831, 2835, 2840, 2842, 2844, 2846, 2848, 2850, 2859, 2863, 2865, 2868, 2871, 2874, 2877, 2885, 2886, 2888, 2889, 2891, 2892, 2894, 2895, 2897, 2898, 2900, 2905, 2907, 2909, 2911, 2915, 2916, 2919, 2922, 2925, 2928, 2930, 2932, 2934, 2936, 2938, 2940, 2943, 2946, 2950, 2952, 2954, 2957, 2960, 2964, 2966, 2968, 2970, 2972, 2974, 2976, 2978, 2980, 2982, 2984, 2986, 2988, 2990, 2992, 2994, 2996, 2999, 3003, 3005, 3008, 3011, 3014, 3017, 3019, 3021, 3023, 3025, 3029, 3035, 3037, 3040, 3043, 3046, 3049, 3052, 3056, 3057, 3060, 3063, 3067, 3068, 3071, 3074, 3077, 3080, 3083, 3086, 3089, 3092, 3094, 3096, 3101, 3102, 3104, 3108, 3110, 3112, 3114, 3116, 3118, 3120, 3122, 3124, 3126, 3128, 3132, 3136, 3142, 3146, 3150, 3151, 3154, 3157, 3160, 3164, 3166, 3169, 3172, 3175, 3178, 3181, 3184, 3188, 3190, 3193, 3196, 3199, 3202, 3205, 3208, 3210, 3212, 3214 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 298, 0, -1, 295, -1, 116, 300, 302, 301, 488, 299, 297, -1, -1, 299, 690, -1, 299, 416, -1, 299, 495, -1, 299, 384, -1, 299, 350, -1, 299, 737, -1, 551, -1, 117, 766, 297, -1, 118, 766, 766, 766, 297, -1, 62, 304, 297, -1, 542, -1, 540, -1, 63, 306, 297, -1, 542, -1, 306, 440, -1, 306, 530, -1, 306, 504, -1, 306, 350, -1, 306, 737, -1, 64, 308, 297, -1, 765, -1, 695, -1, 65, 310, 297, -1, 366, -1, 310, 508, -1, 310, 520, -1, 310, 350, -1, 310, 737, -1, 66, 620, 620, 620, 297, -1, 67, 551, 766, 313, 297, -1, -1, 766, -1, 68, 612, 297, -1, 69, 316, 297, -1, 321, -1, 317, -1, 314, -1, 316, 350, -1, 316, 737, -1, 70, 686, 297, -1, 71, 670, 297, -1, 72, 670, 297, -1, 73, 765, 297, -1, 74, 297, -1, 75, 323, 297, -1, 517, -1, 510, -1, 518, -1, 76, 325, 326, 297, -1, 318, -1, 448, -1, 319, -1, 492, -1, 77, 328, 297, -1, -1, 328, 332, -1, 328, 329, -1, 328, 327, -1, 78, 330, 297, -1, 332, -1, 330, 395, -1, 79, 332, 297, -1, 728, -1, 419, -1, 80, 766, 766, 327, 297, -1, 81, 766, 297, -1, 82, 659, 297, -1, 83, 338, 337, 297, -1, 342, -1, 337, 690, -1, 337, 746, -1, 337, 742, -1, 337, 350, -1, 337, 737, -1, 337, 650, -1, 551, -1, 84, 341, 340, 297, -1, -1, 497, -1, 552, -1, 85, 343, 297, -1, 55, -1, 49, -1, 23, -1, 86, 345, 346, 297, -1, 643, -1, 644, -1, 637, -1, -1, 322, -1, 724, -1, 87, 620, 620, 348, 297, -1, -1, 348, 650, -1, 88, 670, 670, 670, 297, -1, 89, 351, 297, -1, -1, 351, 765, -1, 90, 353, 297, -1, -1, 353, 307, -1, 353, 430, -1, 353, 454, -1, 353, 335, -1, 353, 650, -1, 353, 350, -1, 353, 737, -1, 91, 517, 297, -1, 93, 356, 297, -1, -1, 356, 454, -1, 356, 582, -1, 356, 430, -1, 356, 673, -1, 356, 553, -1, 356, 557, -1, 356, 597, -1, 356, 352, -1, 356, 633, -1, 356, 716, -1, 356, 678, -1, 356, 760, -1, 356, 440, -1, 356, 522, -1, 356, 335, -1, 356, 350, -1, 356, 737, -1, 92, 358, 297, -1, -1, 430, -1, 94, 360, 297, -1, 20, -1, 50, -1, 57, -1, 95, 362, 297, -1, 766, -1, 466, -1, 96, 542, 297, -1, 97, 365, 297, -1, -1, 365, 311, -1, 365, 620, -1, 98, 766, 367, 297, -1, -1, 404, -1, 99, 765, 369, 297, -1, -1, 741, -1, 100, 371, 297, -1, 670, -1, 578, -1, 101, 373, 297, -1, 670, -1, 578, -1, 102, 375, 297, -1, 670, -1, 578, -1, 103, 377, 297, -1, 670, -1, 578, -1, 104, 379, 297, -1, 542, -1, 540, -1, 105, 381, 297, -1, -1, 381, 620, -1, 106, 383, 297, -1, 9, -1, 34, -1, 47, -1, 107, 388, 385, 297, -1, 339, -1, 385, 690, -1, 385, 350, -1, 385, 650, -1, 385, 737, -1, 108, 387, 297, -1, 765, -1, 695, -1, 551, -1, 220, 390, 297, -1, -1, 390, 437, -1, 390, 432, -1, 390, 661, -1, 390, 435, -1, 390, 592, -1, 390, 590, -1, 390, 405, -1, 390, 472, -1, 390, 476, -1, 390, 574, -1, 390, 572, -1, 390, 420, -1, 390, 350, -1, 390, 737, -1, 109, 392, 297, -1, 428, -1, 434, -1, 392, 428, -1, 392, 434, -1, 110, 394, 297, -1, 26, -1, 27, -1, 40, -1, 111, 396, 397, 398, 399, 297, -1, 423, -1, 426, -1, -1, 483, -1, -1, 587, -1, -1, 589, -1, 112, 401, 297, -1, -1, 401, 517, -1, 113, 403, 297, -1, 620, -1, 403, 650, -1, 114, 670, 297, -1, 119, 668, 424, 424, 406, 297, -1, 656, -1, 682, -1, 406, 350, -1, 406, 737, -1, 120, 408, 297, -1, 20, -1, 50, -1, 57, -1, 121, 410, 411, 412, 297, -1, 533, -1, 344, -1, 692, -1, 524, -1, 644, -1, 569, -1, 704, -1, -1, 378, -1, 502, -1, 122, 414, 297, -1, 644, -1, 637, -1, 631, -1, 567, -1, 561, -1, 414, 724, -1, 414, 322, -1, 123, 670, 297, -1, 124, 493, 301, 417, 297, -1, 709, -1, 417, 690, -1, 417, 336, -1, 417, 350, -1, 417, 737, -1, 125, 491, 423, 297, -1, 126, 297, -1, 129, 421, 297, -1, 422, -1, 421, 359, -1, 421, 407, -1, 421, 609, -1, 421, 334, -1, 421, 349, -1, 421, 439, -1, 421, 333, -1, 421, 711, -1, 421, 754, -1, 421, 350, -1, 421, 650, -1, 421, 737, -1, 421, 451, -1, 551, -1, 552, -1, 130, 425, 297, -1, 423, -1, 428, -1, 434, -1, 131, 427, 297, -1, 423, -1, 427, 359, -1, 427, 407, -1, 427, 609, -1, 427, 334, -1, 427, 349, -1, 427, 439, -1, 427, 333, -1, 427, 711, -1, 427, 754, -1, 427, 350, -1, 427, 650, -1, 427, 737, -1, 132, 423, 429, 297, -1, -1, 497, -1, 127, 431, 297, -1, 422, -1, 426, -1, 431, 347, -1, 431, 402, -1, 431, 585, -1, 431, 605, -1, 431, 621, -1, 431, 659, -1, 431, 675, -1, 431, 350, -1, 431, 737, -1, 128, 668, 424, 433, 297, -1, 656, -1, 682, -1, 433, 350, -1, 433, 737, -1, 474, -1, 732, -1, 391, -1, 478, -1, 594, -1, 133, 668, 424, 436, 297, -1, 656, -1, 682, -1, 436, 350, -1, 436, 737, -1, 134, 668, 424, 438, 297, -1, 656, -1, 682, -1, 438, 350, -1, 438, 737, -1, 135, 766, 766, 327, 297, -1, 136, 441, 442, 297, -1, 643, -1, 644, -1, 644, -1, 704, -1, 442, 378, -1, 442, 502, -1, 137, 444, 297, -1, 712, -1, 444, 413, -1, 767, 446, 295, -1, -1, 446, 766, -1, 446, 765, -1, 446, 764, -1, 446, 445, -1, 138, 643, 297, -1, 139, 670, 297, -1, 140, 670, 670, 297, -1, 141, 297, -1, 142, 452, 297, -1, 428, -1, 434, -1, 143, 297, -1, 144, 464, 455, 297, -1, 750, -1, 744, -1, 455, 718, -1, 455, 604, -1, 455, 635, -1, 455, 716, -1, 455, 386, -1, 455, 650, -1, 455, 350, -1, 455, 737, -1, 148, 465, 457, 297, -1, -1, 456, -1, 750, -1, 145, 459, 297, -1, 456, -1, 459, 386, -1, 459, 716, -1, 459, 650, -1, 459, 350, -1, 146, 461, 297, -1, -1, 461, 456, -1, 147, 463, 297, -1, -1, 463, 456, -1, 463, 460, -1, 463, 350, -1, 463, 737, -1, 551, -1, 312, -1, 552, -1, 536, -1, 150, 467, 297, -1, 766, -1, 467, 395, -1, 149, 469, 297, -1, -1, 469, 766, -1, 469, 466, -1, 469, 468, -1, 151, 471, 297, -1, -1, 471, 623, -1, 471, 627, -1, 471, 700, -1, 471, 654, -1, 471, 315, -1, 471, 602, -1, 471, 481, -1, 471, 547, -1, 471, 758, -1, 471, 610, -1, 471, 716, -1, 471, 678, -1, 471, 386, -1, 471, 650, -1, 471, 350, -1, 471, 737, -1, 152, 668, 424, 424, 473, 297, -1, 656, -1, 682, -1, 473, 350, -1, 473, 737, -1, 153, 475, 297, -1, 428, -1, 434, -1, 475, 428, -1, 475, 434, -1, 154, 668, 424, 477, 297, -1, 656, -1, 682, -1, 477, 350, -1, 477, 737, -1, 155, 479, 297, -1, 428, -1, 434, -1, 156, 297, -1, 157, 482, 297, -1, -1, 482, 644, -1, 482, 637, -1, 482, 447, -1, 158, 484, 297, -1, 11, -1, 12, -1, 13, -1, 29, -1, 30, -1, 31, -1, 58, -1, 59, -1, 60, -1, 159, 486, 297, -1, 490, -1, 486, 395, -1, 160, 766, 297, -1, 161, 489, 297, -1, 487, -1, 489, 350, -1, 764, -1, 551, -1, 162, 670, 297, -1, 551, -1, 552, -1, 163, 493, 301, 496, 297, -1, 709, -1, 496, 690, -1, 496, 336, -1, 496, 350, -1, 496, 737, -1, 164, 494, 297, -1, 165, 499, 297, -1, -1, 499, 553, -1, 166, 501, 297, -1, -1, 501, 623, -1, 501, 627, -1, 167, 503, 503, 297, -1, 542, -1, 540, -1, 168, 505, 506, 507, 297, -1, 643, -1, 644, -1, 644, -1, 524, -1, 704, -1, -1, 378, -1, 502, -1, 169, 509, 297, -1, 637, -1, 644, -1, 643, -1, 509, 528, -1, 170, 511, 297, -1, -1, 511, 517, -1, 511, 518, -1, 511, 450, -1, 171, 513, 297, -1, -1, 513, 517, -1, 172, 515, 297, -1, -1, 515, 517, -1, 551, -1, 552, -1, 173, 519, 297, -1, -1, 519, 517, -1, 519, 510, -1, 174, 521, 297, -1, 637, -1, 644, -1, 643, -1, 521, 528, -1, 175, 523, 297, -1, 642, -1, 523, 650, -1, 523, 350, -1, 523, 737, -1, 176, 517, 525, 297, -1, -1, 497, -1, 177, 527, 297, -1, 516, -1, 527, 755, -1, 527, 363, -1, 527, 331, -1, 527, 354, -1, 527, 757, -1, 527, 699, -1, 527, 400, -1, 527, 514, -1, 527, 512, -1, 527, 480, -1, 527, 666, -1, 527, 650, -1, 527, 350, -1, 527, 737, -1, 178, 529, 297, -1, -1, 529, 517, -1, 529, 510, -1, 529, 518, -1, 529, 450, -1, 179, 531, 532, 297, -1, 643, -1, 644, -1, -1, 378, -1, 502, -1, 180, 534, 535, 297, -1, 643, -1, 644, -1, 637, -1, 517, -1, 510, -1, 518, -1, 181, 552, 537, 297, -1, 766, -1, 537, 766, -1, 182, 539, 297, -1, -1, 539, 542, -1, 539, 540, -1, 539, 538, -1, 183, 541, 297, -1, 542, -1, 541, 395, -1, 543, -1, 670, -1, 184, 544, 544, 544, 297, -1, 670, -1, 731, -1, 730, -1, 185, 546, 297, -1, -1, 546, 657, -1, 186, 548, 297, -1, -1, 548, 644, -1, 548, 637, -1, 548, 758, -1, 548, 481, -1, 187, 550, 297, -1, 764, -1, 550, 395, -1, 764, -1, 549, -1, 663, -1, 764, -1, 549, -1, 188, 565, 554, 297, -1, 481, -1, 554, 361, -1, 554, 559, -1, 554, 430, -1, 554, 553, -1, 554, 454, -1, 554, 352, -1, 554, 650, -1, 554, 350, -1, 554, 737, -1, 189, 556, 297, -1, 567, -1, 556, 559, -1, 556, 361, -1, 556, 650, -1, 556, 350, -1, 190, 565, 558, 297, -1, 498, -1, 558, 430, -1, 558, 352, -1, 558, 650, -1, 558, 350, -1, 558, 737, -1, 191, 382, 560, 297, -1, 378, -1, 560, 724, -1, 560, 322, -1, 192, 562, 297, -1, -1, 562, 566, -1, 562, 567, -1, 193, 564, 297, -1, -1, 564, 567, -1, 564, 561, -1, 564, 350, -1, 564, 737, -1, 551, -1, 312, -1, 552, -1, 536, -1, 194, 566, 568, 297, -1, -1, 567, -1, 456, -1, 750, -1, 195, 297, -1, 196, 571, 297, -1, -1, 571, 644, -1, 571, 610, -1, 197, 668, 573, 297, -1, 424, -1, 573, 350, -1, 573, 737, -1, 198, 668, 424, 575, 297, -1, 656, -1, 682, -1, 575, 350, -1, 575, 737, -1, 199, 577, 297, -1, -1, 577, 670, -1, 577, 578, -1, 577, 576, -1, 201, 579, 297, -1, 670, -1, 579, 395, -1, 200, 581, 297, -1, -1, 581, 669, -1, 581, 449, -1, 581, 350, -1, 202, 583, 297, -1, 642, -1, 583, 736, -1, 583, 650, -1, 583, 350, -1, 583, 737, -1, 203, 413, 670, 297, -1, 204, 586, 297, -1, 364, -1, 586, 650, -1, 205, 588, 297, -1, 43, -1, 46, -1, 44, -1, 45, -1, 35, -1, 37, -1, 38, -1, 36, -1, 206, 620, 297, -1, 207, 668, 424, 424, 591, 297, -1, 656, -1, 682, -1, 591, 350, -1, 591, 737, -1, 208, 668, 424, 424, 593, 297, -1, 656, -1, 682, -1, 593, 350, -1, 593, 737, -1, 209, 766, 595, 359, 297, -1, 428, -1, 434, -1, 210, 765, 297, -1, 211, 598, 297, -1, 464, -1, 598, 454, -1, 598, 553, -1, 598, 557, -1, 598, 352, -1, 598, 633, -1, 598, 599, -1, 598, 335, -1, 598, 350, -1, 598, 737, -1, 212, 659, 297, -1, 215, 601, 297, -1, 740, -1, 601, 395, -1, 213, 739, 729, 603, 297, -1, -1, 734, -1, 214, 740, 729, 297, -1, 216, 606, 297, -1, 618, -1, 606, 650, -1, 217, 608, 297, -1, 378, -1, 608, 413, -1, 218, 766, 297, -1, 219, 611, 297, -1, -1, 611, 644, -1, 611, 610, -1, 611, 570, -1, 221, 613, 297, -1, -1, 613, 688, -1, 222, 615, 297, -1, -1, 615, 620, -1, 615, 616, -1, 615, 614, -1, 223, 617, 297, -1, 620, -1, 617, 395, -1, 224, 619, 297, -1, -1, 619, 620, -1, 241, 766, 766, 297, -1, 225, 622, 297, -1, 618, -1, 622, 650, -1, 226, 624, 297, -1, 642, -1, 624, 393, -1, 624, 736, -1, 624, 629, -1, 624, 386, -1, 624, 370, -1, 624, 372, -1, 624, 374, -1, 624, 376, -1, 624, 303, -1, 624, 650, -1, 624, 350, -1, 624, 737, -1, 227, 626, 297, -1, 644, -1, 626, 386, -1, 626, 629, -1, 626, 370, -1, 626, 372, -1, 626, 374, -1, 626, 376, -1, 626, 303, -1, 626, 650, -1, 626, 350, -1, 228, 642, 628, 297, -1, 500, -1, 628, 650, -1, 628, 350, -1, 628, 737, -1, 229, 382, 630, 297, -1, 378, -1, 502, -1, 630, 724, -1, 630, 322, -1, 230, 632, 297, -1, -1, 632, 643, -1, 632, 644, -1, 231, 634, 297, -1, 644, -1, 643, -1, 634, 357, -1, 634, 430, -1, 634, 454, -1, 634, 352, -1, 634, 648, -1, 634, 485, -1, 634, 650, -1, 634, 737, -1, 634, 350, -1, 232, 636, 297, -1, 644, -1, 643, -1, 636, 736, -1, 636, 629, -1, 636, 386, -1, 636, 370, -1, 636, 372, -1, 636, 374, -1, 636, 376, -1, 636, 303, -1, 636, 650, -1, 636, 350, -1, 636, 737, -1, 233, 638, 297, -1, -1, 638, 644, -1, 638, 643, -1, 234, 642, 637, 297, -1, 235, 641, 297, -1, -1, 641, 644, -1, 641, 631, -1, 641, 350, -1, 641, 737, -1, 551, -1, 312, -1, 552, -1, 536, -1, 236, 643, 645, 297, -1, -1, 644, -1, 456, -1, 750, -1, 237, 765, 647, 297, -1, -1, 741, -1, 239, 649, 297, -1, 653, -1, 649, 395, -1, 238, 652, 651, 297, -1, 729, -1, 651, 596, -1, 651, 734, -1, 651, 650, -1, 651, 350, -1, 551, -1, 552, -1, 240, 655, 297, -1, -1, 655, 633, -1, 655, 430, -1, 655, 454, -1, 655, 352, -1, 655, 335, -1, 655, 648, -1, 655, 485, -1, 655, 600, -1, 655, 650, -1, 655, 350, -1, 655, 737, -1, 492, -1, 448, -1, 319, -1, 318, -1, 415, -1, 324, -1, 242, 658, 297, -1, -1, 658, 656, -1, 658, 682, -1, 243, 620, 660, 297, -1, 620, -1, 660, 650, -1, 244, 668, 424, 662, 297, -1, 657, -1, 545, -1, 662, 350, -1, 662, 737, -1, 245, 664, 665, 297, -1, 764, -1, 549, -1, 765, -1, 695, -1, 246, 667, 297, -1, -1, 667, 517, -1, 551, -1, 247, 670, 670, 734, 297, -1, 766, -1, 115, 766, 766, 297, -1, 248, 766, 766, 297, -1, 249, 766, 766, 297, -1, 250, 674, 297, -1, 765, -1, 674, 673, -1, 674, 765, -1, 674, 454, -1, 251, 676, 297, -1, 364, -1, 676, 650, -1, 551, -1, 252, 679, 297, -1, 677, -1, 679, 639, -1, 679, 756, -1, 679, 309, -1, 679, 350, -1, 679, 737, -1, 253, 681, 297, -1, -1, 681, 526, -1, 681, 350, -1, 681, 737, -1, 254, 683, 297, -1, -1, 656, -1, 255, 750, 685, 297, -1, -1, 718, -1, 256, 687, 297, -1, -1, 702, -1, 257, 689, 297, -1, 702, -1, 689, 684, -1, 258, 691, 297, -1, -1, 691, 762, -1, 691, 350, -1, 691, 737, -1, 259, 693, 694, 297, -1, 643, -1, 644, -1, 637, -1, 404, -1, 694, 724, -1, 694, 322, -1, 261, 698, 297, -1, 260, 697, 297, -1, -1, 697, 765, -1, 697, 695, -1, 697, 696, -1, 765, -1, 698, 395, -1, 262, 517, 297, -1, 263, 701, 297, -1, -1, 701, 633, -1, 701, 430, -1, 701, 454, -1, 701, 352, -1, 701, 307, -1, 701, 599, -1, 701, 335, -1, 701, 648, -1, 701, 485, -1, 701, 600, -1, 701, 650, -1, 701, 350, -1, 701, 737, -1, 264, 703, 297, -1, -1, 703, 718, -1, 265, 705, 297, -1, -1, 705, 409, -1, 705, 706, -1, 266, 707, 708, 297, -1, 524, -1, 644, -1, 569, -1, 704, -1, -1, 378, -1, 502, -1, 267, 710, 297, -1, 580, -1, 710, 420, -1, 710, 418, -1, 710, 680, -1, 710, 389, -1, 710, 350, -1, 710, 737, -1, 268, 766, 297, -1, 269, 713, 714, 297, -1, 413, -1, 584, -1, 413, -1, 584, -1, 404, -1, 270, 766, 766, 766, 766, 766, 766, 297, -1, 271, 717, 297, -1, 382, -1, 717, 607, -1, 717, 443, -1, 717, 350, -1, 717, 737, -1, 272, 719, 720, 721, 722, 723, 297, -1, -1, 671, -1, -1, 672, -1, -1, 380, -1, -1, 587, -1, -1, 589, -1, 273, 725, 725, 297, -1, 517, -1, 510, -1, 518, -1, 274, 727, 297, -1, -1, 727, 344, -1, 727, 692, -1, 727, 453, -1, 275, 297, -1, 327, -1, 468, -1, 538, -1, 576, -1, 614, -1, 696, -1, 276, 297, -1, 277, 297, -1, 278, 733, 297, -1, 428, -1, 434, -1, 733, 428, -1, 733, 434, -1, 279, 735, 297, -1, 17, -1, 10, -1, 16, -1, 48, -1, 54, -1, 56, -1, 61, -1, 33, -1, 22, -1, 25, -1, 19, -1, 42, -1, 14, -1, 15, -1, 21, -1, 7, -1, 280, 297, -1, 281, 738, 297, -1, 764, -1, 738, 766, -1, 738, 765, -1, 738, 764, -1, 738, 445, -1, 551, -1, 312, -1, 552, -1, 536, -1, 282, 765, 297, -1, 283, 748, 752, 743, 297, -1, 470, -1, 743, 690, -1, 743, 355, -1, 743, 350, -1, 743, 650, -1, 743, 737, -1, 284, 745, 297, -1, -1, 745, 750, -1, 745, 744, -1, 285, 747, 297, -1, -1, 747, 640, -1, 747, 625, -1, 747, 462, -1, 747, 458, -1, 747, 563, -1, 747, 555, -1, 747, 350, -1, 747, 737, -1, 551, -1, 552, -1, 286, 749, 751, 297, -1, -1, 339, -1, 287, 753, 297, -1, 32, -1, 41, -1, 39, -1, 51, -1, 53, -1, 8, -1, 28, -1, 18, -1, 24, -1, 52, -1, 288, 332, 297, -1, 289, 542, 297, -1, 290, 516, 670, 528, 297, -1, 291, 517, 297, -1, 292, 759, 297, -1, -1, 759, 644, -1, 759, 637, -1, 759, 481, -1, 293, 761, 297, -1, 726, -1, 761, 305, -1, 761, 440, -1, 761, 530, -1, 761, 504, -1, 761, 350, -1, 761, 737, -1, 294, 763, 297, -1, 715, -1, 763, 320, -1, 763, 646, -1, 763, 368, -1, 763, 650, -1, 763, 350, -1, 763, 737, -1, 3, -1, 6, -1, 4, -1, 5, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 505, 505, 508, 511, 512, 513, 514, 515, 516, 517, 520, 523, 526, 530, 533, 534, 537, 540, 541, 542, 543, 544, 545, 548, 551, 552, 555, 558, 559, 560, 561, 562, 565, 568, 571, 572, 575, 578, 581, 582, 583, 584, 585, 588, 591, 594, 597, 600, 603, 606, 607, 608, 611, 614, 615, 618, 619, 622, 625, 626, 627, 628, 631, 634, 635, 638, 641, 642, 645, 648, 651, 654, 657, 658, 659, 660, 661, 662, 663, 666, 669, 672, 673, 676, 679, 682, 683, 684, 687, 690, 691, 692, 695, 696, 697, 700, 703, 704, 707, 710, 713, 714, 717, 720, 721, 722, 723, 724, 725, 726, 727, 730, 733, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 756, 759, 760, 763, 766, 767, 768, 771, 774, 775, 778, 781, 784, 785, 786, 789, 792, 793, 796, 799, 800, 803, 806, 807, 810, 813, 814, 817, 820, 821, 824, 827, 828, 831, 834, 835, 838, 841, 842, 845, 848, 849, 850, 853, 856, 857, 858, 859, 860, 863, 866, 867, 870, 873, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 893, 896, 897, 898, 899, 902, 905, 906, 907, 910, 913, 914, 917, 918, 921, 922, 925, 926, 929, 932, 933, 936, 939, 940, 943, 946, 950, 951, 952, 953, 956, 959, 960, 961, 964, 968, 969, 970, 973, 974, 975, 976, 979, 980, 981, 984, 987, 988, 989, 990, 991, 992, 993, 996, 999, 1002, 1003, 1004, 1005, 1006, 1009, 1012, 1015, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1034, 1037, 1040, 1043, 1044, 1045, 1048, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1066, 1069, 1070, 1073, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1089, 1092, 1093, 1094, 1095, 1098, 1099, 1100, 1101, 1102, 1105, 1108, 1109, 1110, 1111, 1114, 1117, 1118, 1119, 1120, 1123, 1126, 1129, 1130, 1133, 1134, 1135, 1136, 1139, 1142, 1143, 1146, 1149, 1150, 1151, 1152, 1153, 1156, 1159, 1162, 1165, 1168, 1171, 1172, 1175, 1178, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1193, 1196, 1197, 1198, 1201, 1204, 1205, 1206, 1207, 1208, 1211, 1214, 1215, 1218, 1221, 1222, 1223, 1224, 1225, 1228, 1229, 1232, 1233, 1236, 1239, 1240, 1243, 1246, 1247, 1248, 1249, 1252, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1274, 1278, 1279, 1280, 1281, 1284, 1287, 1288, 1289, 1290, 1293, 1296, 1297, 1298, 1299, 1302, 1305, 1306, 1309, 1312, 1315, 1316, 1317, 1318, 1321, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1335, 1338, 1339, 1342, 1345, 1348, 1349, 1352, 1355, 1358, 1361, 1364, 1367, 1370, 1371, 1372, 1373, 1374, 1377, 1380, 1383, 1384, 1387, 1390, 1391, 1392, 1395, 1398, 1399, 1402, 1405, 1406, 1409, 1410, 1411, 1414, 1415, 1416, 1419, 1422, 1423, 1424, 1425, 1428, 1431, 1432, 1433, 1434, 1437, 1440, 1441, 1444, 1447, 1448, 1451, 1454, 1457, 1460, 1461, 1462, 1465, 1468, 1469, 1470, 1471, 1474, 1477, 1478, 1479, 1480, 1483, 1486, 1487, 1490, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1510, 1513, 1514, 1515, 1516, 1517, 1520, 1523, 1524, 1527, 1528, 1529, 1532, 1535, 1536, 1537, 1540, 1541, 1542, 1545, 1548, 1549, 1552, 1555, 1556, 1557, 1558, 1561, 1564, 1565, 1568, 1569, 1572, 1575, 1576, 1577, 1580, 1583, 1584, 1587, 1590, 1591, 1592, 1593, 1594, 1597, 1600, 1601, 1604, 1605, 1606, 1609, 1610, 1613, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, 1628, 1631, 1632, 1633, 1634, 1635, 1638, 1641, 1642, 1643, 1644, 1645, 1646, 1649, 1652, 1653, 1654, 1657, 1660, 1661, 1662, 1665, 1668, 1669, 1670, 1671, 1672, 1675, 1676, 1680, 1681, 1684, 1687, 1688, 1689, 1690, 1693, 1696, 1699, 1700, 1701, 1704, 1707, 1708, 1709, 1712, 1715, 1716, 1717, 1718, 1721, 1724, 1725, 1726, 1727, 1730, 1733, 1734, 1737, 1740, 1741, 1742, 1743, 1746, 1749, 1750, 1751, 1752, 1753, 1756, 1759, 1762, 1763, 1766, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1779, 1782, 1786, 1787, 1788, 1789, 1792, 1796, 1797, 1798, 1799, 1802, 1805, 1806, 1809, 1812, 1815, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1827, 1830, 1833, 1834, 1837, 1840, 1841, 1844, 1847, 1850, 1851, 1854, 1857, 1858, 1861, 1864, 1867, 1868, 1869, 1870, 1873, 1876, 1877, 1880, 1883, 1884, 1885, 1886, 1889, 1892, 1893, 1896, 1899, 1900, 1903, 1906, 1909, 1910, 1913, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1931, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1946, 1949, 1950, 1951, 1952, 1955, 1958, 1959, 1960, 1961, 1964, 1967, 1968, 1969, 1972, 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2006, 2009, 2010, 2011, 2014, 2017, 2020, 2021, 2022, 2023, 2024, 2027, 2028, 2031, 2032, 2035, 2050, 2051, 2052, 2053, 2056, 2059, 2060, 2063, 2066, 2067, 2070, 2073, 2074, 2075, 2076, 2077, 2080, 2083, 2086, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2103, 2104, 2105, 2106, 2107, 2108, 2111, 2114, 2115, 2116, 2119, 2122, 2123, 2126, 2129, 2130, 2131, 2132, 2135, 2139, 2140, 2143, 2144, 2147, 2150, 2151, 2154, 2157, 2160, 2161, 2164, 2167, 2170, 2173, 2174, 2175, 2176, 2179, 2182, 2183, 2186, 2189, 2192, 2193, 2194, 2195, 2196, 2197, 2200, 2203, 2204, 2205, 2206, 2209, 2212, 2213, 2216, 2219, 2220, 2223, 2226, 2227, 2230, 2233, 2234, 2237, 2240, 2241, 2242, 2243, 2246, 2249, 2250, 2251, 2254, 2255, 2256, 2259, 2262, 2265, 2266, 2267, 2268, 2271, 2272, 2275, 2278, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2297, 2300, 2301, 2304, 2307, 2308, 2309, 2312, 2315, 2316, 2317, 2318, 2321, 2322, 2323, 2326, 2329, 2330, 2331, 2332, 2333, 2334, 2335, 2338, 2341, 2344, 2345, 2348, 2349, 2350, 2353, 2357, 2360, 2361, 2362, 2363, 2364, 2367, 2371, 2372, 2375, 2376, 2379, 2380, 2383, 2384, 2387, 2388, 2391, 2394, 2395, 2396, 2399, 2402, 2403, 2404, 2405, 2408, 2411, 2412, 2413, 2414, 2415, 2416, 2419, 2422, 2425, 2428, 2429, 2430, 2431, 2434, 2437, 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2455, 2458, 2461, 2462, 2463, 2464, 2465, 2468, 2469, 2472, 2473, 2476, 2479, 2482, 2483, 2484, 2485, 2486, 2487, 2490, 2493, 2494, 2495, 2498, 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2512, 2515, 2518, 2521, 2522, 2525, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2540, 2543, 2546, 2549, 2552, 2555, 2556, 2557, 2558, 2561, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2573, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 2585, 2588, 2591, 2594 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "EDIF_TOK_IDENT", "EDIF_TOK_INT", "EDIF_TOK_KEYWORD", "EDIF_TOK_STR", "EDIF_TOK_ANGLE", "EDIF_TOK_BEHAVIOR", "EDIF_TOK_CALCULATED", "EDIF_TOK_CAPACITANCE", "EDIF_TOK_CENTERCENTER", "EDIF_TOK_CENTERLEFT", "EDIF_TOK_CENTERRIGHT", "EDIF_TOK_CHARGE", "EDIF_TOK_CONDUCTANCE", "EDIF_TOK_CURRENT", "EDIF_TOK_DISTANCE", "EDIF_TOK_DOCUMENT", "EDIF_TOK_ENERGY", "EDIF_TOK_EXTEND", "EDIF_TOK_FLUX", "EDIF_TOK_FREQUENCY", "EDIF_TOK_GENERIC", "EDIF_TOK_GRAPHIC", "EDIF_TOK_INDUCTANCE", "EDIF_TOK_INOUT", "EDIF_TOK_INPUT", "EDIF_TOK_LOGICMODEL", "EDIF_TOK_LOWERCENTER", "EDIF_TOK_LOWERLEFT", "EDIF_TOK_LOWERRIGHT", "EDIF_TOK_MASKLAYOUT", "EDIF_TOK_MASS", "EDIF_TOK_MEASURED", "EDIF_TOK_MX", "EDIF_TOK_MXR90", "EDIF_TOK_MY", "EDIF_TOK_MYR90", "EDIF_TOK_NETLIST", "EDIF_TOK_OUTPUT", "EDIF_TOK_PCBLAYOUT", "EDIF_TOK_POWER", "EDIF_TOK_R0", "EDIF_TOK_R180", "EDIF_TOK_R270", "EDIF_TOK_R90", "EDIF_TOK_REQUIRED", "EDIF_TOK_RESISTANCE", "EDIF_TOK_RIPPER", "EDIF_TOK_ROUND", "EDIF_TOK_SCHEMATIC", "EDIF_TOK_STRANGER", "EDIF_TOK_SYMBOLIC", "EDIF_TOK_TEMPERATURE", "EDIF_TOK_TIE", "EDIF_TOK_TIME", "EDIF_TOK_TRUNCATE", "EDIF_TOK_UPPERCENTER", "EDIF_TOK_UPPERLEFT", "EDIF_TOK_UPPERRIGHT", "EDIF_TOK_VOLTAGE", "EDIF_TOK_ACLOAD", "EDIF_TOK_AFTER", "EDIF_TOK_ANNOTATE", "EDIF_TOK_APPLY", "EDIF_TOK_ARC", "EDIF_TOK_ARRAY", "EDIF_TOK_ARRAYMACRO", "EDIF_TOK_ARRAYRELATEDINFO", "EDIF_TOK_ARRAYSITE", "EDIF_TOK_ATLEAST", "EDIF_TOK_ATMOST", "EDIF_TOK_AUTHOR", "EDIF_TOK_BASEARRAY", "EDIF_TOK_BECOMES", "EDIF_TOK_BETWEEN", "EDIF_TOK_BOOLEAN", "EDIF_TOK_BOOLEANDISPLAY", "EDIF_TOK_BOOLEANMAP", "EDIF_TOK_BORDERPATTERN", "EDIF_TOK_BORDERWIDTH", "EDIF_TOK_BOUNDINGBOX", "EDIF_TOK_CELL", "EDIF_TOK_CELLREF", "EDIF_TOK_CELLTYPE", "EDIF_TOK_CHANGE", "EDIF_TOK_CIRCLE", "EDIF_TOK_COLOR", "EDIF_TOK_COMMENT", "EDIF_TOK_COMMENTGRAPHICS", "EDIF_TOK_COMPOUND", "EDIF_TOK_CONNECTLOCATION", "EDIF_TOK_CONTENTS", "EDIF_TOK_CORNERTYPE", "EDIF_TOK_CRITICALITY", "EDIF_TOK_CURRENTMAP", "EDIF_TOK_CURVE", "EDIF_TOK_CYCLE", "EDIF_TOK_DATAORIGIN", "EDIF_TOK_DCFANINLOAD", "EDIF_TOK_DCFANOUTLOAD", "EDIF_TOK_DCMAXFANIN", "EDIF_TOK_DCMAXFANOUT", "EDIF_TOK_DELAY", "EDIF_TOK_DELTA", "EDIF_TOK_DERIVATION", "EDIF_TOK_DESIGN", "EDIF_TOK_DESIGNATOR", "EDIF_TOK_DIFFERENCE", "EDIF_TOK_DIRECTION", "EDIF_TOK_DISPLAY", "EDIF_TOK_DOMINATES", "EDIF_TOK_DOT", "EDIF_TOK_DURATION", "EDIF_TOK_E", "EDIF_TOK_EDIF", "EDIF_TOK_EDIFLEVEL", "EDIF_TOK_EDIFVERSION", "EDIF_TOK_ENCLOSUREDISTANCE", "EDIF_TOK_ENDTYPE", "EDIF_TOK_ENTRY", "EDIF_TOK_EVENT", "EDIF_TOK_EXACTLY", "EDIF_TOK_EXTERNAL", "EDIF_TOK_FABRICATE", "EDIF_TOK_FALSE", "EDIF_TOK_FIGURE", "EDIF_TOK_FIGUREAREA", "EDIF_TOK_FIGUREGROUP", "EDIF_TOK_FIGUREGROUPOBJECT", "EDIF_TOK_FIGUREGROUPOVERRIDE", "EDIF_TOK_FIGUREGROUPREF", "EDIF_TOK_FIGUREPERIMETER", "EDIF_TOK_FIGUREWIDTH", "EDIF_TOK_FILLPATTERN", "EDIF_TOK_FOLLOW", "EDIF_TOK_FORBIDDENEVENT", "EDIF_TOK_GLOBALPORTREF", "EDIF_TOK_GREATERTHAN", "EDIF_TOK_GRIDMAP", "EDIF_TOK_IGNORE", "EDIF_TOK_INCLUDEFIGUREGROUP", "EDIF_TOK_INITIAL", "EDIF_TOK_INSTANCE", "EDIF_TOK_INSTANCEBACKANNOTATE", "EDIF_TOK_INSTANCEGROUP", "EDIF_TOK_INSTANCEMAP", "EDIF_TOK_INSTANCEREF", "EDIF_TOK_INTEGER", "EDIF_TOK_INTEGERDISPLAY", "EDIF_TOK_INTERFACE", "EDIF_TOK_INTERFIGUREGROUPSPACING", "EDIF_TOK_INTERSECTION", "EDIF_TOK_INTRAFIGUREGROUPSPACING", "EDIF_TOK_INVERSE", "EDIF_TOK_ISOLATED", "EDIF_TOK_JOINED", "EDIF_TOK_JUSTIFY", "EDIF_TOK_KEYWORDDISPLAY", "EDIF_TOK_KEYWORDLEVEL", "EDIF_TOK_KEYWORDMAP", "EDIF_TOK_LESSTHAN", "EDIF_TOK_LIBRARY", "EDIF_TOK_LIBRARYREF", "EDIF_TOK_LISTOFNETS", "EDIF_TOK_LISTOFPORTS", "EDIF_TOK_LOADDELAY", "EDIF_TOK_LOGICASSIGN", "EDIF_TOK_LOGICINPUT", "EDIF_TOK_LOGICLIST", "EDIF_TOK_LOGICMAPINPUT", "EDIF_TOK_LOGICMAPOUTPUT", "EDIF_TOK_LOGICONEOF", "EDIF_TOK_LOGICOUTPUT", "EDIF_TOK_LOGICPORT", "EDIF_TOK_LOGICREF", "EDIF_TOK_LOGICVALUE", "EDIF_TOK_LOGICWAVEFORM", "EDIF_TOK_MAINTAIN", "EDIF_TOK_MATCH", "EDIF_TOK_MEMBER", "EDIF_TOK_MINOMAX", "EDIF_TOK_MINOMAXDISPLAY", "EDIF_TOK_MNM", "EDIF_TOK_MULTIPLEVALUESET", "EDIF_TOK_MUSTJOIN", "EDIF_TOK_NAME", "EDIF_TOK_NET", "EDIF_TOK_NETBACKANNOTATE", "EDIF_TOK_NETBUNDLE", "EDIF_TOK_NETDELAY", "EDIF_TOK_NETGROUP", "EDIF_TOK_NETMAP", "EDIF_TOK_NETREF", "EDIF_TOK_NOCHANGE", "EDIF_TOK_NONPERMUTABLE", "EDIF_TOK_NOTALLOWED", "EDIF_TOK_NOTCHSPACING", "EDIF_TOK_NUMBER", "EDIF_TOK_NUMBERDEFINITION", "EDIF_TOK_NUMBERDISPLAY", "EDIF_TOK_OFFPAGECONNECTOR", "EDIF_TOK_OFFSETEVENT", "EDIF_TOK_OPENSHAPE", "EDIF_TOK_ORIENTATION", "EDIF_TOK_ORIGIN", "EDIF_TOK_OVERHANGDISTANCE", "EDIF_TOK_OVERLAPDISTANCE", "EDIF_TOK_OVERSIZE", "EDIF_TOK_OWNER", "EDIF_TOK_PAGE", "EDIF_TOK_PAGESIZE", "EDIF_TOK_PARAMETER", "EDIF_TOK_PARAMETERASSIGN", "EDIF_TOK_PARAMETERDISPLAY", "EDIF_TOK_PATH", "EDIF_TOK_PATHDELAY", "EDIF_TOK_PATHWIDTH", "EDIF_TOK_PERMUTABLE", "EDIF_TOK_PHYSICALDESIGNRULE", "EDIF_TOK_PLUG", "EDIF_TOK_POINT", "EDIF_TOK_POINTDISPLAY", "EDIF_TOK_POINTLIST", "EDIF_TOK_POLYGON", "EDIF_TOK_PORT", "EDIF_TOK_PORTBACKANNOTATE", "EDIF_TOK_PORTBUNDLE", "EDIF_TOK_PORTDELAY", "EDIF_TOK_PORTGROUP", "EDIF_TOK_PORTIMPLEMENTATION", "EDIF_TOK_PORTINSTANCE", "EDIF_TOK_PORTLIST", "EDIF_TOK_PORTLISTALIAS", "EDIF_TOK_PORTMAP", "EDIF_TOK_PORTREF", "EDIF_TOK_PROGRAM", "EDIF_TOK_PROPERTY", "EDIF_TOK_PROPERTYDISPLAY", "EDIF_TOK_PROTECTIONFRAME", "EDIF_TOK_PT", "EDIF_TOK_RANGEVECTOR", "EDIF_TOK_RECTANGLE", "EDIF_TOK_RECTANGLESIZE", "EDIF_TOK_RENAME", "EDIF_TOK_RESOLVES", "EDIF_TOK_SCALE", "EDIF_TOK_SCALEX", "EDIF_TOK_SCALEY", "EDIF_TOK_SECTION", "EDIF_TOK_SHAPE", "EDIF_TOK_SIMULATE", "EDIF_TOK_SIMULATIONINFO", "EDIF_TOK_SINGLEVALUESET", "EDIF_TOK_SITE", "EDIF_TOK_SOCKET", "EDIF_TOK_SOCKETSET", "EDIF_TOK_STATUS", "EDIF_TOK_STEADY", "EDIF_TOK_STRING", "EDIF_TOK_STRINGDISPLAY", "EDIF_TOK_STRONG", "EDIF_TOK_SYMBOL", "EDIF_TOK_SYMMETRY", "EDIF_TOK_TABLE", "EDIF_TOK_TABLEDEFAULT", "EDIF_TOK_TECHNOLOGY", "EDIF_TOK_TEXTHEIGHT", "EDIF_TOK_TIMEINTERVAL", "EDIF_TOK_TIMESTAMP", "EDIF_TOK_TIMING", "EDIF_TOK_TRANSFORM", "EDIF_TOK_TRANSITION", "EDIF_TOK_TRIGGER", "EDIF_TOK_TRUE", "EDIF_TOK_UNCONSTRAINED", "EDIF_TOK_UNDEFINED", "EDIF_TOK_UNION", "EDIF_TOK_UNIT", "EDIF_TOK_UNUSED", "EDIF_TOK_USERDATA", "EDIF_TOK_VERSION", "EDIF_TOK_VIEW", "EDIF_TOK_VIEWLIST", "EDIF_TOK_VIEWMAP", "EDIF_TOK_VIEWREF", "EDIF_TOK_VIEWTYPE", "EDIF_TOK_VISIBLE", "EDIF_TOK_VOLTAGEMAP", "EDIF_TOK_WAVEVALUE", "EDIF_TOK_WEAK", "EDIF_TOK_WEAKJOINED", "EDIF_TOK_WHEN", "EDIF_TOK_WRITTEN", "')'", "$accept", "PopC", "Edif", "_Edif", "EdifFileName", "EdifLevel", "EdifVersion", "AcLoad", "_AcLoad", "After", "_After", "Annotate", "_Annotate", "Apply", "_Apply", "Arc", "Array", "_Array", "ArrayMacro", "ArrayRelInfo", "_ArrayRelInfo", "ArraySite", "AtLeast", "AtMost", "Author", "BaseArray", "Becomes", "_Becomes", "Between", "__Between", "_Between", "Boolean", "_Boolean", "BooleanDisp", "_BooleanDisp", "BooleanMap", "BooleanValue", "BorderPat", "BorderWidth", "BoundBox", "Cell", "_Cell", "CellNameDef", "CellRef", "_CellRef", "CellNameRef", "CellType", "_CellType", "Change", "__Change", "_Change", "Circle", "_Circle", "Color", "Comment", "_Comment", "CommGraph", "_CommGraph", "Compound", "Contents", "_Contents", "ConnectLoc", "_ConnectLoc", "CornerType", "_CornerType", "Criticality", "_Criticality", "CurrentMap", "Curve", "_Curve", "Cycle", "_Cycle", "DataOrigin", "_DataOrigin", "DcFanInLoad", "_DcFanInLoad", "DcFanOutLoad", "_DcFanOutLoad", "DcMaxFanIn", "_DcMaxFanIn", "DcMaxFanOut", "_DcMaxFanOut", "Delay", "_Delay", "Delta", "_Delta", "Derivation", "_Derivation", "Design", "_Design", "Designator", "_Designator", "DesignNameDef", "DesignRule", "_DesignRule", "Difference", "_Difference", "Direction", "_Direction", "Display", "_Display", "_DisplayJust", "_DisplayOrien", "_DisplayOrg", "Dominates", "_Dominates", "Dot", "_Dot", "Duration", "EncloseDist", "_EncloseDist", "EndType", "_EndType", "Entry", "___Entry", "__Entry", "_Entry", "Event", "_Event", "Exactly", "External", "_External", "Fabricate", "False", "FigGrp", "_FigGrp", "FigGrpNameDef", "FigGrpNameRef", "FigGrpObj", "_FigGrpObj", "FigGrpOver", "_FigGrpOver", "FigGrpRef", "_FigGrpRef", "Figure", "_Figure", "FigureArea", "_FigureArea", "FigureOp", "FigurePerim", "_FigurePerim", "FigureWidth", "_FigureWidth", "FillPattern", "Follow", "__Follow", "_Follow", "Forbidden", "_Forbidden", "Form", "_Form", "GlobPortRef", "GreaterThan", "GridMap", "Ignore", "IncFigGrp", "_IncFigGrp", "Initial", "Instance", "_Instance", "InstanceRef", "_InstanceRef", "InstBackAn", "_InstBackAn", "InstGroup", "_InstGroup", "InstMap", "_InstMap", "InstNameDef", "InstNameRef", "IntDisplay", "_IntDisplay", "Integer", "_Integer", "Interface", "_Interface", "InterFigGrp", "_InterFigGrp", "Intersection", "_Intersection", "IntraFigGrp", "_IntraFigGrp", "Inverse", "_Inverse", "Isolated", "Joined", "_Joined", "Justify", "_Justify", "KeywordDisp", "_KeywordDisp", "KeywordLevel", "KeywordMap", "_KeywordMap", "KeywordName", "LayerNameDef", "LessThan", "LibNameDef", "LibNameRef", "Library", "_Library", "LibraryRef", "ListOfNets", "_ListOfNets", "ListOfPorts", "_ListOfPorts", "LoadDelay", "_LoadDelay", "LogicAssn", "___LogicAssn", "__LogicAssn", "_LogicAssn", "LogicIn", "_LogicIn", "LogicList", "_LogicList", "LogicMapIn", "_LogicMapIn", "LogicMapOut", "_LogicMapOut", "LogicNameDef", "LogicNameRef", "LogicOneOf", "_LogicOneOf", "LogicOut", "_LogicOut", "LogicPort", "_LogicPort", "LogicRef", "_LogicRef", "LogicValue", "_LogicValue", "LogicWave", "_LogicWave", "Maintain", "__Maintain", "_Maintain", "Match", "__Match", "_Match", "Member", "_Member", "MiNoMa", "_MiNoMa", "MiNoMaDisp", "_MiNoMaDisp", "MiNoMaValue", "Mnm", "_Mnm", "MultValSet", "_MultValSet", "MustJoin", "_MustJoin", "Name", "_Name", "NameDef", "NameRef", "Net", "_Net", "NetBackAn", "_NetBackAn", "NetBundle", "_NetBundle", "NetDelay", "_NetDelay", "NetGroup", "_NetGroup", "NetMap", "_NetMap", "NetNameDef", "NetNameRef", "NetRef", "_NetRef", "NoChange", "NonPermut", "_NonPermut", "NotAllowed", "_NotAllowed", "NotchSpace", "_NotchSpace", "Number", "_Number", "NumbDisplay", "_NumbDisplay", "NumberDefn", "_NumberDefn", "OffPageConn", "_OffPageConn", "OffsetEvent", "OpenShape", "_OpenShape", "Orientation", "_Orientation", "Origin", "OverhngDist", "_OverhngDist", "OverlapDist", "_OverlapDist", "Oversize", "_Oversize", "Owner", "Page", "_Page", "PageSize", "ParamDisp", "_ParamDisp", "Parameter", "_Parameter", "ParamAssign", "Path", "_Path", "PathDelay", "_PathDelay", "PathWidth", "Permutable", "_Permutable", "Plug", "_Plug", "Point", "_Point", "PointDisp", "_PointDisp", "PointList", "_PointList", "PointValue", "Polygon", "_Polygon", "Port", "_Port", "PortBackAn", "_PortBackAn", "PortBundle", "_PortBundle", "PortDelay", "_PortDelay", "PortGroup", "_PortGroup", "PortImpl", "_PortImpl", "PortInst", "_PortInst", "PortList", "_PortList", "PortListAls", "PortMap", "_PortMap", "PortNameDef", "PortNameRef", "PortRef", "_PortRef", "Program", "_Program", "PropDisplay", "_PropDisplay", "Property", "_Property", "PropNameDef", "PropNameRef", "ProtectFrame", "_ProtectFrame", "Range", "RangeVector", "_RangeVector", "Rectangle", "_Rectangle", "RectSize", "_RectSize", "Rename", "__Rename", "_Rename", "Resolves", "_Resolves", "RuleNameDef", "Scale", "ScaledInt", "ScaleX", "ScaleY", "Section", "_Section", "Shape", "_Shape", "SimNameDef", "Simulate", "_Simulate", "SimulInfo", "_SimulInfo", "SingleValSet", "_SingleValSet", "Site", "_Site", "Socket", "_Socket", "SocketSet", "_SocketSet", "Status", "_Status", "Steady", "__Steady", "_Steady", "StrDisplay", "String", "_String", "_StrDisplay", "Strong", "Symbol", "_Symbol", "Symmetry", "_Symmetry", "Table", "_Table", "TableDeflt", "__TableDeflt", "_TableDeflt", "Technology", "_Technology", "TextHeight", "TimeIntval", "__TimeIntval", "_TimeIntval", "TimeStamp", "Timing", "_Timing", "Transform", "_TransX", "_TransY", "_TransDelta", "_TransOrien", "_TransOrg", "Transition", "_Transition", "Trigger", "_Trigger", "True", "TypedValue", "Unconstrained", "Undefined", "Union", "_Union", "Unit", "_Unit", "Unused", "UserData", "_UserData", "ValueNameDef", "ValueNameRef", "Version", "View", "_View", "ViewList", "_ViewList", "ViewMap", "_ViewMap", "ViewNameDef", "ViewNameRef", "ViewRef", "_ViewRef", "ViewType", "_ViewType", "Visible", "VoltageMap", "WaveValue", "Weak", "WeakJoined", "_WeakJoined", "When", "_When", "Written", "_Written", "Ident", "Str", "Int", "Keyword", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 41 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint16 yyr1[] = { 0, 296, 297, 298, 299, 299, 299, 299, 299, 299, 299, 300, 301, 302, 303, 304, 304, 305, 306, 306, 306, 306, 306, 306, 307, 308, 308, 309, 310, 310, 310, 310, 310, 311, 312, 313, 313, 314, 315, 316, 316, 316, 316, 316, 317, 318, 319, 320, 321, 322, 323, 323, 323, 324, 325, 325, 326, 326, 327, 328, 328, 328, 328, 329, 330, 330, 331, 332, 332, 333, 334, 335, 336, 337, 337, 337, 337, 337, 337, 337, 338, 339, 340, 340, 341, 342, 343, 343, 343, 344, 345, 345, 345, 346, 346, 346, 347, 348, 348, 349, 350, 351, 351, 352, 353, 353, 353, 353, 353, 353, 353, 353, 354, 355, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, 357, 358, 358, 359, 360, 360, 360, 361, 362, 362, 363, 364, 365, 365, 365, 366, 367, 367, 368, 369, 369, 370, 371, 371, 372, 373, 373, 374, 375, 375, 376, 377, 377, 378, 379, 379, 380, 381, 381, 382, 383, 383, 383, 384, 385, 385, 385, 385, 385, 386, 387, 387, 388, 389, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 391, 392, 392, 392, 392, 393, 394, 394, 394, 395, 396, 396, 397, 397, 398, 398, 399, 399, 400, 401, 401, 402, 403, 403, 404, 405, 406, 406, 406, 406, 407, 408, 408, 408, 409, 410, 410, 410, 411, 411, 411, 411, 412, 412, 412, 413, 414, 414, 414, 414, 414, 414, 414, 415, 416, 417, 417, 417, 417, 417, 418, 419, 420, 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, 421, 422, 423, 424, 425, 425, 425, 426, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 427, 428, 429, 429, 430, 431, 431, 431, 431, 431, 431, 431, 431, 431, 431, 431, 432, 433, 433, 433, 433, 434, 434, 434, 434, 434, 435, 436, 436, 436, 436, 437, 438, 438, 438, 438, 439, 440, 441, 441, 442, 442, 442, 442, 443, 444, 444, 445, 446, 446, 446, 446, 446, 447, 448, 449, 450, 451, 452, 452, 453, 454, 455, 455, 455, 455, 455, 455, 455, 455, 455, 455, 456, 457, 457, 457, 458, 459, 459, 459, 459, 459, 460, 461, 461, 462, 463, 463, 463, 463, 463, 464, 464, 465, 465, 466, 467, 467, 468, 469, 469, 469, 469, 470, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, 472, 473, 473, 473, 473, 474, 475, 475, 475, 475, 476, 477, 477, 477, 477, 478, 479, 479, 480, 481, 482, 482, 482, 482, 483, 484, 484, 484, 484, 484, 484, 484, 484, 484, 485, 486, 486, 487, 488, 489, 489, 490, 491, 492, 493, 494, 495, 496, 496, 496, 496, 496, 497, 498, 499, 499, 500, 501, 501, 501, 502, 503, 503, 504, 505, 505, 506, 506, 506, 507, 507, 507, 508, 509, 509, 509, 509, 510, 511, 511, 511, 511, 512, 513, 513, 514, 515, 515, 516, 517, 518, 519, 519, 519, 520, 521, 521, 521, 521, 522, 523, 523, 523, 523, 524, 525, 525, 526, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 528, 529, 529, 529, 529, 529, 530, 531, 531, 532, 532, 532, 533, 534, 534, 534, 535, 535, 535, 536, 537, 537, 538, 539, 539, 539, 539, 540, 541, 541, 542, 542, 543, 544, 544, 544, 545, 546, 546, 547, 548, 548, 548, 548, 548, 549, 550, 550, 551, 551, 551, 552, 552, 553, 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, 555, 556, 556, 556, 556, 556, 557, 558, 558, 558, 558, 558, 558, 559, 560, 560, 560, 561, 562, 562, 562, 563, 564, 564, 564, 564, 564, 565, 565, 566, 566, 567, 568, 568, 568, 568, 569, 570, 571, 571, 571, 572, 573, 573, 573, 574, 575, 575, 575, 575, 576, 577, 577, 577, 577, 578, 579, 579, 580, 581, 581, 581, 581, 582, 583, 583, 583, 583, 583, 584, 585, 586, 586, 587, 588, 588, 588, 588, 588, 588, 588, 588, 589, 590, 591, 591, 591, 591, 592, 593, 593, 593, 593, 594, 595, 595, 596, 597, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 599, 600, 601, 601, 602, 603, 603, 604, 605, 606, 606, 607, 608, 608, 609, 610, 611, 611, 611, 611, 612, 613, 613, 614, 615, 615, 615, 615, 616, 617, 617, 618, 619, 619, 620, 621, 622, 622, 623, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 625, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627, 628, 628, 628, 628, 629, 630, 630, 630, 630, 631, 632, 632, 632, 633, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, 635, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 638, 638, 638, 639, 640, 641, 641, 641, 641, 641, 642, 642, 643, 643, 644, 645, 645, 645, 645, 646, 647, 647, 648, 649, 649, 650, 651, 651, 651, 651, 651, 652, 653, 654, 655, 655, 655, 655, 655, 655, 655, 655, 655, 655, 655, 655, 656, 656, 656, 656, 656, 656, 657, 658, 658, 658, 659, 660, 660, 661, 662, 662, 662, 662, 663, 664, 664, 665, 665, 666, 667, 667, 668, 669, 670, 670, 671, 672, 673, 674, 674, 674, 674, 675, 676, 676, 677, 678, 679, 679, 679, 679, 679, 679, 680, 681, 681, 681, 681, 682, 683, 683, 684, 685, 685, 686, 687, 687, 688, 689, 689, 690, 691, 691, 691, 691, 692, 693, 693, 693, 694, 694, 694, 695, 696, 697, 697, 697, 697, 698, 698, 699, 700, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 701, 702, 703, 703, 704, 705, 705, 705, 706, 707, 707, 707, 707, 708, 708, 708, 709, 710, 710, 710, 710, 710, 710, 710, 711, 712, 713, 713, 714, 714, 714, 715, 716, 717, 717, 717, 717, 717, 718, 719, 719, 720, 720, 721, 721, 722, 722, 723, 723, 724, 725, 725, 725, 726, 727, 727, 727, 727, 728, 729, 729, 729, 729, 729, 729, 730, 731, 732, 733, 733, 733, 733, 734, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 736, 737, 738, 738, 738, 738, 738, 739, 739, 740, 740, 741, 742, 743, 743, 743, 743, 743, 743, 744, 745, 745, 745, 746, 747, 747, 747, 747, 747, 747, 747, 747, 747, 748, 749, 750, 751, 751, 752, 753, 753, 753, 753, 753, 753, 753, 753, 753, 753, 754, 755, 756, 757, 758, 759, 759, 759, 759, 760, 761, 761, 761, 761, 761, 761, 761, 762, 763, 763, 763, 763, 763, 763, 763, 764, 765, 766, 767 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 7, 0, 2, 2, 2, 2, 2, 2, 1, 3, 5, 3, 1, 1, 3, 1, 2, 2, 2, 2, 2, 3, 1, 1, 3, 1, 2, 2, 2, 2, 5, 5, 0, 1, 3, 3, 1, 1, 1, 2, 2, 3, 3, 3, 3, 2, 3, 1, 1, 1, 4, 1, 1, 1, 1, 3, 0, 2, 2, 2, 3, 1, 2, 3, 1, 1, 5, 3, 3, 4, 1, 2, 2, 2, 2, 2, 2, 1, 4, 0, 1, 1, 3, 1, 1, 1, 4, 1, 1, 1, 0, 1, 1, 5, 0, 2, 5, 3, 0, 2, 3, 0, 2, 2, 2, 2, 2, 2, 2, 3, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 1, 3, 1, 1, 1, 3, 1, 1, 3, 3, 0, 2, 2, 4, 0, 1, 4, 0, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 1, 1, 3, 0, 2, 3, 1, 1, 1, 4, 1, 2, 2, 2, 2, 3, 1, 1, 1, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1, 2, 2, 3, 1, 1, 1, 6, 1, 1, 0, 1, 0, 1, 0, 1, 3, 0, 2, 3, 1, 2, 3, 6, 1, 1, 2, 2, 3, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 3, 1, 1, 1, 1, 1, 2, 2, 3, 5, 1, 2, 2, 2, 2, 4, 2, 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 1, 1, 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 0, 1, 3, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 1, 1, 2, 2, 1, 1, 1, 1, 1, 5, 1, 1, 2, 2, 5, 1, 1, 2, 2, 5, 4, 1, 1, 1, 1, 2, 2, 3, 1, 2, 3, 0, 2, 2, 2, 2, 3, 3, 4, 2, 3, 1, 1, 2, 4, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 0, 1, 1, 3, 1, 2, 2, 2, 2, 3, 0, 2, 3, 0, 2, 2, 2, 2, 1, 1, 1, 1, 3, 1, 2, 3, 0, 2, 2, 2, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 1, 1, 2, 2, 3, 1, 1, 2, 2, 5, 1, 1, 2, 2, 3, 1, 1, 2, 3, 0, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 3, 3, 1, 2, 1, 1, 3, 1, 1, 5, 1, 2, 2, 2, 2, 3, 3, 0, 2, 3, 0, 2, 2, 4, 1, 1, 5, 1, 1, 1, 1, 1, 0, 1, 1, 3, 1, 1, 1, 2, 3, 0, 2, 2, 2, 3, 0, 2, 3, 0, 2, 1, 1, 3, 0, 2, 2, 3, 1, 1, 1, 2, 3, 1, 2, 2, 2, 4, 0, 1, 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 2, 2, 2, 2, 4, 1, 1, 0, 1, 1, 4, 1, 1, 1, 1, 1, 1, 4, 1, 2, 3, 0, 2, 2, 2, 3, 1, 2, 1, 1, 5, 1, 1, 1, 3, 0, 2, 3, 0, 2, 2, 2, 2, 3, 1, 2, 1, 1, 1, 1, 1, 4, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 2, 2, 2, 2, 4, 1, 2, 2, 2, 2, 2, 4, 1, 2, 2, 3, 0, 2, 2, 3, 0, 2, 2, 2, 2, 1, 1, 1, 1, 4, 0, 1, 1, 1, 2, 3, 0, 2, 2, 4, 1, 2, 2, 5, 1, 1, 2, 2, 3, 0, 2, 2, 2, 3, 1, 2, 3, 0, 2, 2, 2, 3, 1, 2, 2, 2, 2, 4, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 3, 6, 1, 1, 2, 2, 6, 1, 1, 2, 2, 5, 1, 1, 3, 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, 2, 5, 0, 1, 4, 3, 1, 2, 3, 1, 2, 3, 3, 0, 2, 2, 2, 3, 0, 2, 3, 0, 2, 2, 2, 3, 1, 2, 3, 0, 2, 4, 3, 1, 2, 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 1, 2, 2, 2, 4, 1, 1, 2, 2, 3, 0, 2, 2, 3, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 2, 2, 4, 3, 0, 2, 2, 2, 2, 1, 1, 1, 1, 4, 0, 1, 1, 1, 4, 0, 1, 3, 1, 2, 4, 1, 2, 2, 2, 2, 1, 1, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, 0, 2, 2, 4, 1, 2, 5, 1, 1, 2, 2, 4, 1, 1, 1, 1, 3, 0, 2, 1, 5, 1, 4, 4, 4, 3, 1, 2, 2, 2, 3, 1, 2, 1, 3, 1, 2, 2, 2, 2, 2, 3, 0, 2, 2, 2, 3, 0, 1, 4, 0, 1, 3, 0, 1, 3, 1, 2, 3, 0, 2, 2, 2, 4, 1, 1, 1, 1, 2, 2, 3, 3, 0, 2, 2, 2, 1, 2, 3, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 0, 2, 3, 0, 2, 2, 4, 1, 1, 1, 1, 0, 1, 1, 3, 1, 2, 2, 2, 2, 2, 2, 3, 4, 1, 1, 1, 1, 1, 8, 3, 1, 2, 2, 2, 2, 7, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 4, 1, 1, 1, 3, 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 3, 1, 1, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, 2, 2, 2, 1, 1, 1, 1, 3, 5, 1, 2, 2, 2, 2, 2, 3, 0, 2, 2, 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 4, 0, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 5, 3, 3, 0, 2, 2, 2, 3, 1, 2, 2, 2, 2, 2, 2, 3, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint16 yydefact[] = { 0, 0, 0, 1126, 0, 0, 0, 590, 11, 591, 589, 1, 0, 587, 883, 0, 882, 0, 0, 0, 2, 586, 588, 1127, 0, 0, 885, 884, 1128, 0, 0, 0, 0, 213, 211, 212, 593, 279, 592, 0, 946, 881, 0, 0, 0, 4, 285, 0, 0, 215, 214, 940, 947, 0, 12, 0, 457, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 284, 292, 289, 290, 295, 286, 287, 291, 288, 296, 293, 297, 294, 443, 444, 445, 446, 447, 448, 449, 450, 451, 0, 0, 217, 216, 13, 0, 456, 458, 0, 0, 0, 929, 3, 9, 8, 6, 7, 5, 10, 0, 0, 0, 0, 891, 0, 136, 137, 138, 0, 232, 233, 234, 0, 0, 0, 848, 0, 0, 0, 1054, 0, 0, 0, 68, 67, 442, 683, 686, 684, 685, 679, 681, 682, 680, 0, 0, 0, 218, 455, 0, 184, 0, 462, 0, 0, 0, 70, 0, 0, 100, 102, 135, 231, 0, 727, 59, 396, 564, 656, 737, 942, 1022, 1023, 1024, 1025, 1026, 0, 1027, 843, 987, 1129, 1053, 1058, 1057, 1056, 1055, 345, 262, 1021, 1101, 678, 0, 0, 210, 0, 176, 0, 0, 0, 0, 928, 931, 932, 930, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 842, 847, 844, 846, 845, 0, 0, 687, 82, 84, 175, 178, 179, 177, 180, 0, 0, 256, 0, 465, 0, 1119, 0, 69, 892, 99, 333, 0, 58, 62, 61, 60, 0, 395, 398, 399, 397, 0, 0, 563, 567, 566, 565, 571, 572, 0, 655, 659, 658, 657, 0, 736, 740, 739, 738, 941, 944, 945, 943, 0, 1051, 1037, 1048, 1049, 1038, 1036, 1046, 1050, 1044, 1045, 1043, 1047, 1039, 1040, 1041, 1042, 0, 344, 349, 348, 347, 346, 0, 0, 0, 83, 664, 980, 0, 0, 255, 258, 259, 257, 260, 464, 467, 468, 466, 469, 0, 0, 0, 0, 1118, 1120, 1124, 1122, 1121, 1123, 1125, 0, 64, 0, 393, 0, 569, 0, 0, 0, 574, 576, 575, 0, 661, 0, 742, 701, 1035, 747, 0, 463, 81, 0, 0, 0, 186, 912, 979, 985, 984, 982, 981, 983, 986, 0, 80, 0, 0, 151, 837, 63, 65, 392, 394, 568, 570, 1028, 1029, 0, 660, 662, 741, 743, 470, 0, 0, 663, 667, 666, 665, 0, 460, 0, 264, 278, 0, 0, 0, 0, 73, 0, 47, 0, 0, 152, 0, 838, 0, 0, 0, 0, 0, 263, 271, 268, 269, 274, 265, 266, 270, 277, 267, 275, 272, 276, 273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 199, 193, 198, 188, 190, 187, 194, 195, 197, 196, 192, 191, 189, 200, 0, 911, 914, 913, 915, 88, 87, 86, 0, 0, 1076, 72, 77, 79, 74, 78, 76, 75, 0, 0, 150, 836, 573, 0, 0, 261, 0, 0, 0, 0, 0, 0, 320, 355, 356, 0, 318, 321, 322, 319, 889, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 526, 0, 506, 85, 1085, 0, 0, 0, 1063, 352, 0, 0, 202, 203, 299, 424, 425, 0, 434, 435, 0, 0, 1031, 1032, 0, 354, 0, 0, 0, 0, 0, 0, 0, 647, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 501, 504, 887, 0, 0, 0, 525, 529, 539, 530, 528, 533, 536, 535, 534, 538, 537, 532, 540, 527, 531, 0, 0, 0, 383, 0, 627, 0, 822, 1075, 1083, 1080, 1079, 1082, 1081, 1078, 1077, 1084, 0, 890, 201, 204, 205, 0, 300, 423, 426, 427, 433, 699, 700, 0, 1030, 1033, 1034, 281, 0, 282, 283, 0, 0, 0, 0, 0, 0, 0, 917, 866, 865, 868, 867, 0, 864, 863, 314, 315, 0, 324, 325, 0, 329, 330, 0, 0, 429, 430, 646, 648, 649, 0, 651, 652, 0, 0, 578, 870, 878, 877, 0, 0, 0, 507, 0, 0, 436, 0, 0, 0, 0, 0, 0, 1096, 1098, 1099, 1097, 1091, 1093, 1092, 1094, 1100, 1095, 0, 401, 1065, 0, 0, 374, 0, 0, 0, 0, 606, 0, 0, 0, 766, 0, 994, 298, 0, 280, 0, 227, 228, 0, 0, 54, 0, 55, 0, 0, 0, 918, 0, 313, 316, 317, 323, 326, 327, 328, 331, 332, 0, 419, 420, 428, 431, 432, 650, 653, 654, 0, 689, 690, 0, 694, 695, 0, 0, 876, 879, 880, 66, 112, 142, 219, 221, 500, 502, 503, 505, 886, 888, 948, 1102, 1104, 1090, 0, 114, 1064, 1068, 1067, 1069, 1066, 1070, 0, 370, 391, 390, 0, 0, 373, 378, 375, 377, 376, 380, 382, 386, 384, 385, 387, 635, 634, 637, 0, 0, 605, 610, 608, 607, 609, 623, 626, 630, 629, 628, 631, 830, 829, 832, 0, 0, 0, 0, 0, 0, 765, 773, 775, 769, 770, 771, 772, 767, 768, 774, 787, 821, 825, 824, 823, 826, 698, 226, 229, 230, 45, 46, 56, 0, 57, 254, 351, 461, 916, 418, 421, 422, 688, 691, 692, 693, 696, 697, 577, 579, 869, 871, 872, 0, 438, 581, 0, 729, 0, 0, 851, 0, 950, 1106, 400, 406, 416, 414, 408, 409, 407, 411, 402, 403, 415, 405, 413, 404, 412, 417, 410, 0, 0, 0, 371, 0, 372, 0, 183, 182, 0, 996, 0, 0, 639, 638, 0, 640, 0, 141, 140, 0, 0, 834, 833, 0, 835, 0, 16, 15, 0, 155, 154, 0, 158, 157, 0, 161, 160, 0, 164, 163, 0, 0, 53, 0, 0, 0, 41, 0, 40, 39, 0, 0, 0, 1060, 1059, 0, 0, 828, 827, 0, 752, 0, 0, 903, 905, 0, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 129, 130, 122, 117, 127, 115, 128, 119, 120, 116, 121, 123, 118, 125, 124, 131, 126, 0, 561, 1086, 1088, 369, 181, 172, 173, 174, 0, 0, 0, 995, 999, 998, 997, 1000, 379, 381, 636, 139, 0, 619, 0, 622, 624, 625, 831, 14, 153, 156, 159, 162, 0, 782, 783, 0, 786, 788, 789, 734, 0, 923, 0, 48, 38, 42, 43, 0, 817, 437, 441, 440, 439, 580, 585, 583, 582, 584, 0, 718, 643, 728, 732, 731, 730, 0, 0, 751, 761, 763, 757, 758, 759, 760, 756, 753, 755, 762, 754, 764, 475, 777, 0, 0, 0, 0, 850, 856, 861, 855, 853, 854, 858, 859, 852, 857, 860, 862, 0, 0, 0, 904, 908, 909, 906, 910, 907, 0, 0, 949, 955, 957, 962, 954, 952, 953, 959, 956, 960, 951, 958, 961, 963, 1105, 1109, 1108, 1107, 0, 0, 0, 302, 303, 0, 0, 335, 336, 389, 0, 388, 0, 518, 633, 632, 0, 0, 0, 669, 703, 0, 0, 792, 791, 0, 896, 1017, 1111, 0, 560, 562, 1089, 0, 171, 0, 0, 342, 725, 0, 0, 167, 166, 0, 0, 618, 621, 620, 0, 480, 479, 781, 785, 784, 0, 37, 965, 0, 924, 44, 0, 0, 35, 0, 719, 0, 207, 208, 209, 0, 1052, 0, 776, 779, 778, 780, 0, 453, 459, 1062, 1061, 0, 715, 849, 0, 840, 0, 0, 28, 0, 0, 0, 26, 25, 0, 0, 71, 103, 105, 108, 110, 106, 107, 109, 111, 0, 0, 0, 0, 0, 0, 301, 304, 311, 305, 306, 307, 308, 309, 310, 312, 968, 0, 337, 338, 1072, 0, 360, 359, 517, 520, 519, 521, 595, 0, 472, 612, 0, 668, 672, 671, 670, 673, 702, 710, 711, 707, 704, 705, 706, 709, 708, 712, 133, 790, 801, 796, 793, 794, 795, 798, 797, 799, 800, 895, 899, 897, 898, 0, 0, 0, 0, 1110, 1112, 1116, 1113, 1115, 1114, 1117, 1087, 0, 0, 989, 990, 0, 341, 343, 724, 726, 165, 496, 509, 0, 51, 50, 52, 1014, 1013, 1015, 0, 0, 0, 733, 735, 0, 922, 350, 816, 819, 818, 0, 36, 717, 642, 645, 644, 206, 474, 476, 477, 452, 454, 714, 716, 839, 841, 148, 0, 0, 27, 31, 29, 30, 32, 0, 0, 24, 713, 874, 0, 0, 0, 223, 144, 676, 0, 745, 0, 722, 749, 0, 901, 0, 0, 334, 339, 340, 0, 0, 0, 1002, 358, 367, 365, 362, 363, 366, 364, 361, 368, 594, 603, 601, 596, 598, 600, 599, 597, 602, 604, 0, 611, 616, 614, 613, 615, 617, 0, 134, 0, 0, 0, 1016, 1018, 1020, 1019, 0, 18, 0, 482, 483, 550, 548, 549, 0, 251, 250, 249, 248, 247, 0, 0, 993, 991, 992, 0, 0, 0, 49, 0, 478, 0, 926, 964, 966, 34, 0, 149, 0, 491, 493, 492, 0, 513, 515, 514, 820, 542, 0, 873, 875, 97, 222, 224, 0, 675, 677, 0, 721, 723, 748, 750, 900, 902, 0, 0, 967, 969, 970, 1071, 1074, 1073, 0, 0, 804, 803, 0, 1003, 1004, 471, 473, 132, 93, 92, 90, 91, 357, 936, 934, 935, 0, 17, 22, 19, 21, 20, 23, 0, 487, 485, 484, 486, 551, 552, 0, 246, 253, 252, 0, 0, 988, 0, 495, 499, 497, 498, 508, 511, 510, 1012, 0, 925, 927, 147, 490, 494, 512, 516, 0, 1103, 0, 0, 143, 145, 146, 744, 746, 0, 237, 0, 236, 238, 0, 972, 974, 973, 975, 976, 0, 802, 812, 814, 808, 809, 810, 811, 807, 806, 813, 805, 815, 0, 0, 1005, 1006, 94, 0, 95, 937, 0, 523, 488, 489, 0, 547, 674, 225, 353, 920, 541, 546, 544, 543, 545, 96, 98, 0, 0, 556, 554, 555, 243, 239, 241, 240, 242, 641, 977, 978, 0, 720, 0, 0, 169, 1007, 1008, 89, 933, 939, 938, 524, 0, 481, 0, 921, 0, 558, 557, 559, 0, 244, 0, 245, 971, 893, 0, 0, 1009, 1010, 522, 919, 0, 553, 235, 894, 168, 170, 1011, 0, 33, 1001 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 21, 2, 58, 6, 31, 18, 797, 893, 1268, 1391, 1078, 1186, 1070, 1182, 1518, 925, 1305, 914, 851, 915, 916, 615, 616, 324, 917, 1141, 1287, 617, 695, 819, 174, 211, 249, 330, 555, 135, 72, 73, 950, 310, 398, 364, 198, 303, 227, 399, 460, 1388, 1467, 1551, 1207, 1515, 74, 75, 117, 952, 1097, 557, 750, 867, 1252, 1382, 76, 121, 778, 884, 558, 1339, 1439, 1183, 1421, 326, 403, 799, 896, 800, 899, 801, 902, 802, 905, 989, 1135, 1589, 1611, 877, 976, 107, 199, 762, 873, 152, 359, 395, 484, 515, 1043, 1164, 22, 33, 49, 95, 149, 559, 651, 1209, 1336, 1407, 439, 689, 77, 125, 1452, 1524, 1576, 1606, 1277, 1399, 618, 108, 235, 360, 136, 361, 392, 393, 34, 531, 604, 35, 47, 485, 591, 953, 1100, 441, 619, 486, 442, 624, 443, 627, 78, 954, 1101, 1217, 981, 1131, 185, 224, 1018, 620, 388, 1498, 420, 487, 1389, 955, 1221, 674, 871, 579, 675, 769, 879, 580, 676, 1105, 755, 253, 332, 175, 212, 671, 746, 444, 711, 488, 521, 445, 631, 489, 524, 560, 854, 918, 50, 93, 1060, 1171, 56, 45, 57, 1172, 390, 621, 154, 349, 109, 237, 304, 1231, 1375, 1049, 1166, 1002, 1143, 1271, 1393, 1483, 1558, 1326, 1423, 1291, 1411, 561, 653, 562, 654, 504, 1292, 1293, 1412, 1327, 1427, 956, 1107, 1484, 1596, 455, 505, 1433, 1513, 1272, 1396, 1489, 1525, 1572, 1604, 787, 967, 176, 213, 1144, 334, 1145, 262, 338, 644, 726, 855, 919, 36, 12, 492, 649, 957, 1229, 581, 678, 958, 1232, 779, 990, 784, 888, 582, 680, 1111, 773, 679, 882, 1529, 1030, 1160, 446, 538, 447, 637, 177, 214, 267, 342, 306, 352, 959, 1113, 1278, 1210, 1340, 96, 147, 150, 448, 720, 449, 723, 490, 599, 221, 960, 1116, 1085, 1061, 1176, 856, 1158, 1359, 1211, 1342, 982, 1134, 79, 857, 924, 1008, 1149, 178, 215, 272, 344, 1343, 1442, 195, 1212, 1345, 858, 927, 583, 682, 859, 1050, 804, 1003, 809, 909, 961, 1117, 1360, 1458, 1019, 1156, 1072, 584, 684, 928, 789, 683, 891, 327, 405, 1063, 1179, 80, 179, 129, 1180, 861, 930, 622, 645, 727, 1096, 1334, 450, 646, 9, 15, 25, 564, 655, 493, 389, 263, 1462, 1548, 962, 1120, 1214, 1347, 932, 862, 933, 362, 396, 623, 701, 1507, 1598, 1010, 1152, 1298, 1416, 110, 157, 1390, 1475, 1554, 26, 180, 216, 39, 565, 863, 934, 1153, 1299, 1219, 1348, 1453, 1532, 1584, 236, 307, 81, 1132, 1279, 1410, 240, 764, 878, 1363, 1463, 1549, 1590, 1613, 1623, 1142, 1294, 1123, 1263, 137, 181, 340, 341, 491, 528, 223, 295, 1046, 82, 131, 923, 1177, 404, 468, 672, 1222, 1352, 469, 510, 509, 970, 872, 1128, 570, 669, 83, 567, 1074, 568, 866, 935, 966, 1124, 206, 241, 38, 27, 116, 189 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -1333 static const yytype_int16 yypact[] = { 41, 152, 149, -1333, 176, 81, 305, -1333, -1333, -1333, -1333, -1333, 33, -1333, -1333, 59, -1333, 148, 317, 101, -1333, -1333, -1333, -1333, 437, 150, -1333, -1333, -1333, 148, 148, 304, 81, 312, -1333, -1333, -1333, -1333, -1333, 33, -1333, -1333, 148, 150, 316, -1333, -1333, 1508, 1780, 272, -1333, -1333, -1333, 150, -1333, 148, -1333, 122, 715, 148, 148, 111, -1333, 997, 1020, 148, 148, 152, 148, 176, 300, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, 1588, 280, -1333, -1333, 150, -1333, -1333, 152, 152, 152, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 148, 150, 148, 111, -1333, 36, -1333, -1333, -1333, 150, -1333, -1333, -1333, 150, 148, 150, -1333, 1023, 150, 66, -1333, 150, 150, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, 260, 150, -1333, -1333, 424, -1333, 317, -1333, 317, 273, 439, -1333, 148, 111, -1333, -1333, -1333, -1333, 439, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 310, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 148, 150, -1333, 81, -1333, 441, 254, 254, 266, -1333, -1333, -1333, -1333, 150, 150, 150, 150, 416, 49, 115, 91, 801, 77, 437, 2006, -1333, -1333, -1333, -1333, -1333, 71, 148, -1333, 376, -1333, -1333, -1333, -1333, -1333, -1333, 343, 445, -1333, 445, -1333, 148, -1333, 158, -1333, -1333, -1333, -1333, 300, -1333, -1333, -1333, -1333, 148, -1333, -1333, -1333, -1333, 276, 144, -1333, -1333, -1333, -1333, -1333, -1333, 111, -1333, -1333, -1333, -1333, 260, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, 150, 81, 150, -1333, -1333, -1333, 546, 152, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 148, 437, 437, 437, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 33, -1333, 33, -1333, 33, -1333, 150, 150, 144, -1333, -1333, -1333, 33, -1333, 33, -1333, -1333, -1333, -1333, 150, -1333, -1333, 132, 152, 152, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 468, -1333, 148, 150, 306, 306, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 144, -1333, -1333, -1333, -1333, -1333, 111, 111, -1333, -1333, -1333, -1333, 81, -1333, 1442, -1333, -1333, 1794, 519, 832, 940, -1333, 148, -1333, 437, 150, -1333, 150, -1333, 150, 111, 111, 150, 1196, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 152, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, 152, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 148, 150, -1333, -1333, -1333, 150, 321, -1333, 1196, 81, 1196, 1196, 148, 1196, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, 461, -1333, 1198, -1333, -1333, -1333, 322, 867, 148, -1333, -1333, 150, 1263, -1333, -1333, 376, -1333, -1333, 1263, -1333, -1333, 150, 1196, -1333, -1333, 1263, -1333, 342, 461, 1545, 1545, 1545, 461, 1545, -1333, 130, 1545, 461, 461, -29, 300, 81, 276, -1333, 150, -1333, -1333, -1333, 81, 276, 81, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 1879, 444, 466, -1333, 425, -1333, 382, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 540, -1333, -1333, -1333, -1333, 150, -1333, -1333, 1545, 111, 111, 42, 111, 111, 111, 1276, -1333, -1333, -1333, -1333, 130, -1333, -1333, -1333, -1333, 130, -1333, -1333, 130, -1333, -1333, 1545, 130, -1333, -1333, -1333, -1333, -1333, 130, -1333, -1333, 1545, 1545, -1333, -1333, -1333, -1333, 130, 150, 150, -1333, 150, 63, -1333, 63, 63, 63, 150, 150, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, 186, 529, -1333, 653, 833, 529, 605, -1333, 171, 529, 581, -1333, 783, -1333, -1333, 150, -1333, 130, -1333, -1333, 150, 150, -1333, 53, -1333, 150, 150, 150, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 130, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 130, -1333, -1333, 130, -1333, -1333, -75, 361, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 990, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 81, -34, -1333, -1333, 59, 548, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 442, 460, 548, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 539, 523, 93, 93, 93, 93, 548, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 543, -1333, -1333, 108, -1333, 108, 108, -1333, 152, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 1584, 148, 81, -1333, 150, -1333, 150, -1333, -1333, 894, -1333, 708, 252, -1333, -1333, 150, -1333, 150, -1333, -1333, 561, 46, -1333, -1333, 150, -1333, 150, -1333, -1333, 150, -1333, -1333, 150, -1333, -1333, 150, -1333, -1333, 150, -1333, -1333, 26, 86, -1333, 431, 421, 150, -1333, 130, -1333, -1333, 531, 281, 152, -1333, -1333, 1023, -73, -1333, -1333, 631, -1333, 512, 762, -1333, -1333, 481, 365, 588, 454, -1333, 76, 104, 108, 108, 108, 108, 108, 108, 104, 437, 418, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 51, -1333, -1333, 424, -1333, -1333, -1333, -1333, -1333, 150, 436, 561, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 523, -1333, -31, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 523, -1333, -1333, -31, -1333, -1333, -1333, -1333, 150, 453, 150, -1333, -1333, -1333, -1333, 529, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 148, 321, -1333, -1333, -1333, -1333, -1333, 711, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 726, 176, 529, 81, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 620, 108, 152, -1333, -1333, -1333, -1333, -1333, -1333, 59, 454, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 260, 150, 691, -1333, -1333, 751, -85, -1333, -1333, -1333, -115, -1333, 726, -1333, -1333, -1333, 568, 562, 635, -1333, -1333, 449, 1253, -1333, -1333, 97, -1333, -1333, -1333, 448, -1333, -1333, -1333, 150, -1333, 384, -24, -1333, -1333, -24, 150, -1333, -1333, 950, 950, -1333, -1333, -1333, 523, -1333, -1333, -1333, -1333, -1333, -122, -1333, -1333, 150, -1333, -1333, 150, 86, 148, 150, -1333, -77, -1333, -1333, -1333, 150, -1333, -90, -1333, -1333, -1333, -1333, 33, -1333, -1333, -1333, -1333, 33, -1333, -1333, 33, -1333, 148, 409, -1333, 530, 111, 150, -1333, -1333, 150, 260, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 260, 260, 675, 553, 553, 675, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 99, -1333, -1333, -1333, 812, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 679, -1333, -1333, 946, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 651, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 34, 276, 104, 104, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 1014, 671, -1333, -1333, 634, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, 950, 150, 453, -1333, -1333, -119, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 684, 255, 255, -1333, -1333, -1333, -1333, -1333, 150, 624, -1333, -1333, -1333, -117, 260, -117, -1333, -1333, -1333, -117, -1333, -117, -1333, -1333, -117, -1333, -117, 269, -1333, -1333, -1333, 428, 529, 104, 560, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -98, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, 255, 150, 255, -1333, -1333, -1333, -1333, 739, -1333, -64, -1333, -1333, 26, -1333, -1333, -31, -1333, -1333, -1333, -1333, -1333, 111, 111, -1333, -1333, -1333, 150, 114, 64, -1333, 150, -1333, -127, -1333, -1333, -1333, -1333, 150, -1333, -52, -1333, -1333, -1333, -52, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, 28, -1333, -1333, -46, -1333, -1333, -1333, -1333, -1333, -1333, 383, 890, -1333, -1333, -1333, -1333, -1333, -1333, 1023, 657, -1333, -1333, 148, -1333, 564, -1333, -1333, -1333, 11, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 684, -1333, -1333, -1333, -1333, -1333, -1333, 81, 26, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333, -1333, 150, 150, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 534, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 113, -1333, -117, 260, -1333, -1333, -1333, -1333, -1333, 255, -1333, 890, -1333, -1333, 150, -1333, -1333, -1333, -1333, 26, 150, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 148, 148, -1333, 725, -1333, 150, -1333, -1333, -31, 376, -1333, -1333, 150, -1333, -1333, -1333, -1333, 577, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 260, 950, -1333, -1333, -1333, 26, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, 150, 148, -1333, -1333, 272, -1333, -1333, -1333, -1333, -1333, 150, -1333, 150, -1333, 260, -1333, -1333, -1333, 150, -1333, 150, -1333, -1333, -1333, 150, -46, -1333, 280, -1333, -1333, 150, -1333, -1333, -1333, -1333, -1333, -1333, 150, -1333, -1333 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -1333, -25, -1333, -1333, -1333, 8, -1333, -906, -1333, -1333, -1333, -265, -1333, -1333, -1333, -1333, 173, -1333, -1333, -1333, -1333, -1333, 223, 139, -1333, -1333, -996, -1333, -1333, -1333, -1333, 645, -1333, -1333, -1333, -1333, -168, 470, 473, -285, 599, -1333, -1333, -91, -1333, -1333, -1333, -1333, -557, -1333, -1333, -1333, -1333, 504, 1011, -1333, -878, -1333, -1333, -1333, -1333, -1333, -1333, -310, -1333, -316, -1333, -1333, -291, -1333, -1333, -1333, -1333, -1333, -902, -1333, -901, -1333, -896, -1333, -893, -1333, -891, -1333, -1333, -1333, -630, -1333, -1333, -1333, -666, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -26, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -890, -1333, -1333, 527, -1333, -1333, -1333, -1333, -1333, -284, -1333, -1333, -1333, -1333, -1333, -1333, 528, -1333, -11, 3, 1663, -1333, -7, -1333, 1085, -1333, -880, -1333, -1333, -1333, 1301, -1333, -1333, -1333, -1333, 544, -1043, -1333, -1333, -1333, -1333, 716, -1333, -1333, 329, -1333, -570, -1333, -1333, -1333, -872, -1333, 308, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 4, -1333, 180, -1333, 745, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -834, -1333, -1333, -1333, -871, -1333, -1333, -1333, -1333, -1333, -1333, 263, 858, -1333, -1333, -1333, -517, -1333, -1333, -1333, -1333, -1202, -181, -428, -1333, -1333, -1333, -1333, -1333, -1109, -1333, -1333, -1333, -1333, -1333, -99, -514, -1097, -1333, -1333, -1333, -1333, -1333, -1332, -1333, -1333, -1333, -1227, -1333, -420, -1333, -1333, -1333, -1333, -1333, -665, -1333, 769, -1333, -193, -1333, -209, -1333, 90, -1333, -1333, -1333, -1333, 355, -1333, 903, 128, -1025, -1333, -1333, -1333, -141, -1333, -242, -1333, -287, -1333, -1333, -1333, 55, 123, -674, -1333, -502, -1333, -1333, -1333, -1333, -1333, -1333, 813, -1333, 472, -1333, -1333, -1333, -1333, -1333, -251, -1333, -1333, -560, -1333, -582, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -83, 105, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 656, -864, -1333, -1333, -1333, 830, -1333, -1333, -1333, -155, -1333, -210, -1333, -1333, -113, -1333, -1333, -1333, -105, -1333, -889, -1333, -213, -1333, -803, -1333, -1333, -1333, -874, -1333, -1333, -1333, -1333, -679, -882, 502, -1333, -1333, -1333, -699, -1333, 767, -1333, -1333, -1333, -1333, -1333, 845, 339, -1333, -942, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -1333, 902, -1333, 141, -1333, -1333, -44, -1333, -1333, -1333, -1333, 213, -1333, -1333, -1333, 411, -1333, -1333, -1333, -1333, -1333, -1333, -1333, -189, -1333, -363, -1333, -1333, -214, 873, -1333, -1333, -1333, -1333, -1333, -195, -1333, -1300, -1333, -1333, -1333, -1333, 904, -1333, 712, -1333, -1333, -1333, -1333, -706, -1333, -1248, -1333, -1333, -1333, -1333, -1333, -980, -186, -1333, -1333, -1333, -912, -1333, -1333, -1333, -1333, -467, -1333, -1089, 1032, -1333, -1333, -241, 742, -1333, -1333, -235, -1333, -1333, -1333, -1333, -1333, -770, -1333, -1333, -1333, 727, -1333, -1333, -1333, 203, -1333, -1333, -1333, -1333, -1333, 1551, 12, 347, -1333 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -1 static const yytype_uint16 yytable[] = { 41, 592, 275, 883, 261, 273, 785, 1147, 756, 514, 232, 1027, 771, 52, 51, 1351, 803, 1001, 54, 892, 260, 1036, 71, 1148, 1236, 1038, 1039, 1005, 97, 1288, 648, 1040, 99, 105, 1041, 46, 40, 656, 1044, 658, 864, 1290, 23, 250, 1138, 1023, 312, 335, 317, 3, 1058, 1419, 1057, 28, 1082, 28, 1081, 1102, 1059, 345, 1031, 1093, 1083, 1084, 1118, 23, 3, 3, 138, 3, 28, 183, 23, 151, 3, 28, 183, 23, 331, 3, 853, 1270, 417, 23, 3, 1022, 1138, 1133, 159, 3, 942, 1243, 162, 1486, 1516, 28, 164, 28, 1275, 881, 165, 1092, 167, 23, 3, 182, 184, 3, 190, 191, 192, 3, 1482, 608, 673, 28, 3, 3, 1528, 28, 1384, 67, 193, 1028, 196, 609, 1432, 1062, 1505, 163, 988, 1087, 203, 1155, 1189, 1296, 844, 735, 845, 737, 739, 741, 843, 187, 19, 887, 843, 37, 28, 11, 1531, 681, 28, 1355, 219, 3, 642, 1, 1213, 681, 37, 964, 200, 681, 201, 908, 929, 643, 20, 1220, 226, 869, 681, 20, 229, 920, 20, 1385, 20, 3, 1216, 612, 242, 243, 244, 245, 247, 252, 258, 265, 270, 274, 1577, 1000, 1488, 194, 1510, 20, 169, 251, 1512, 1216, 115, 988, 1371, 20, 114, 32, 114, 466, 309, 62, 314, 643, 993, 613, 323, 1196, 20, 62, 20, 62, 20, 771, 1580, 1197, 114, 754, 277, 278, 114, 320, 32, 4, 1285, 1088, 299, 1253, 1241, 1251, 677, 940, 1139, 20, 1242, 1254, 1255, 62, 1260, 20, 4, 4, 869, 346, 1496, 1496, 161, 321, 3, 114, 62, 1042, 1108, 4, 20, 1114, 1000, 754, 4, 194, 347, 20, 384, 4, 1303, 62, 348, 1228, 351, 747, 28, 1557, 357, 1285, 1139, 754, 1286, 1286, 4, 687, 171, 4, 264, 1386, 264, 4, 1309, 170, 256, 257, 4, 4, 209, 1502, 371, 370, 373, 372, 375, 374, 1329, 376, 377, 1246, 1500, 1599, 380, 379, 382, 381, 24, 5, 681, 20, 383, 228, 1350, 386, 20, 20, 1583, 20, 367, 368, 369, 1223, 650, 173, 24, 4, 681, 20, 401, 657, 20, 3, 20, 947, 1478, 1369, 1465, 1367, 1379, 5, 1378, 268, 7, 1370, 20, 20, 14, 20, 62, 781, 29, 677, 296, 412, 1383, 1544, 437, 453, 20, 463, 1607, 647, 42, 43, 472, 385, 473, 20, 474, 1394, 1397, 477, 20, 1174, 1184, 53, 1449, 114, 20, 410, 20, 322, 67, 5, 339, 62, 673, 1403, 98, 1491, 1566, 343, 112, 113, 20, 20, 20, 69, 126, 127, 471, 130, 1568, 20, 1256, 1492, 336, 337, 7, 17, 67, 20, 133, 20, 378, 1075, 350, 1422, 608, 609, 30, 507, 754, 610, 840, 69, 1425, 1429, 4, 23, 104, 20, 512, 936, 1424, 1428, 513, 478, 69, 20, 62, 937, 7, 7, 7, 158, 257, 160, 529, 1601, 28, 44, 20, 69, 407, 1384, 48, 1550, 1459, 166, 479, 1603, 55, 94, 188, 339, 554, 20, 518, 752, 611, 577, 148, 1552, 1016, 587, 588, 681, 938, 168, 246, 480, 593, 481, 62, 596, 612, 194, 1469, 600, 1473, 1487, 1275, 208, 197, 940, 1468, 1264, 1472, 634, 1016, 1362, 168, 681, 37, 339, 217, 234, 652, 613, 1051, 408, 409, 28, 308, 4, 62, 936, 3, 603, 62, 1450, 239, 62, 62, 937, 302, 225, 133, 305, 874, 1533, 1066, 20, 67, 475, 476, 482, 1535, 397, 69, 1358, 1537, 1538, 1593, 255, 1159, 685, 1539, 1522, 20, 1540, 686, 202, 20, 1542, 62, 300, 301, 849, 1594, 134, 20, 1076, 1322, 688, 1052, 895, 1456, 1323, 939, 1553, 319, 1276, 402, 218, 673, 530, 1556, 940, 702, 670, 946, 894, 333, 705, 218, 1401, 708, 67, 1053, 20, 714, 37, 62, 569, 251, 911, 717, 912, 673, 614, 1265, 913, 681, 677, 483, 728, 731, 732, 1289, 733, 734, 1266, 736, 738, 740, 742, 743, 744, 63, 62, 677, 942, 114, 943, 1574, 1582, 1386, 790, 745, 1055, 69, 748, 1573, 1079, 760, 766, 1007, 776, 876, 782, 20, 796, 37, 807, 20, 1076, 812, 7, 813, 988, 366, 816, 817, 1015, 62, 353, 821, 822, 823, 354, 824, 1009, 1048, 67, 946, 791, 792, 793, 794, 1605, 825, 673, 1174, 758, 69, 134, 1122, 790, 62, 828, 452, 1095, 831, 104, 774, 834, 836, 104, 20, 1130, 256, 257, 7, 7, 754, 20, 1220, 400, 869, 1067, 4, 1151, 1181, 790, 62, 850, 69, 20, 62, 840, 69, 1230, 869, 69, 69, 791, 792, 793, 794, 1563, 20, 1161, 1162, 758, 20, 1033, 62, 20, 20, 840, 62, 470, 1406, 692, 693, 1163, 697, 698, 699, 1075, 1275, 791, 792, 793, 794, 758, 69, 1016, 1016, 758, 355, 681, 62, 937, 875, 1068, 1338, 936, 774, 681, 20, 1341, 938, 1137, 62, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1541, 1275, 910, 1136, 775, 62, 1406, 356, 69, 757, 1432, 207, 62, 772, 938, 7, 1461, 788, 795, 210, 1194, 1547, 20, 62, 7, 511, 938, 67, 869, 1016, 101, 940, 681, 869, 20, 69, 62, 525, 1588, 1239, 1193, 694, 818, 940, 315, 1276, 1200, 102, 62, 20, 949, 67, 936, 977, 971, 1281, 972, 1355, 1283, 62, 937, 979, 984, 457, 248, 986, 586, 987, 795, 1187, 413, 991, 1201, 414, 994, 942, 995, 67, 775, 996, 62, 67, 997, 939, 20, 998, 103, 1127, 999, 458, 868, 20, 1004, 1190, 795, 459, 1011, 938, 1012, 67, 1523, 1017, 1021, 67, 415, 1499, 1503, 1029, 20, 62, 1035, 973, 8, 1054, 940, 1265, 1069, 1077, 1091, 1034, 69, 1368, 1346, 1034, 69, 67, 1266, 418, 758, 1051, 62, 440, 759, 978, 20, 1098, 974, 67, 20, 1099, 898, 901, 904, 907, 419, 1034, 69, 696, 297, 975, 1125, 1565, 626, 629, 222, 633, 20, 1115, 639, 1129, 20, 3, 885, 1202, 62, 254, 820, 1121, 69, 156, 1295, 1479, 67, 1140, 231, 1203, 1555, 1185, 128, 1480, 69, 104, 20, 1244, 1204, 1052, 1146, 765, 1333, 673, 259, 1150, 768, 1154, 20, 1372, 1400, 69, 1335, 1337, 1405, 946, 1095, 1408, 69, 969, 1112, 1567, 67, 1053, 1205, 20, 153, 155, 155, 69, 328, 1165, 20, 992, 571, 806, 572, 921, 772, 118, 691, 681, 69, 20, 1578, 172, 269, 1167, 1353, 266, 1409, 62, 1612, 1622, 69, 1245, 20, 62, 937, 788, 1595, 1086, 122, 713, 194, 69, 1354, 271, 20, 119, 421, 1344, 67, 722, 725, 1313, 120, 1392, 573, 20, 1602, 839, 574, 1314, 1402, 870, 69, 835, 1482, 788, 100, 106, 123, 1191, 1192, 938, 788, 1206, 1261, 124, 20, 62, 963, 880, 1224, 759, 1355, 1527, 1526, 1188, 1233, 276, 111, 1238, 1249, 69, 575, 1259, 20, 889, 758, 1267, 168, 1417, 576, 1274, 423, 238, 1280, 20, 1414, 1282, 1284, 406, 1457, 1104, 69, 1109, 1109, 1455, 1104, 425, 1285, 886, 1025, 1286, 1297, 1436, 681, 1300, 20, 0, 1301, 1302, 1262, 1307, 0, 1308, 0, 4, 838, 1311, 0, 1312, 0, 788, 0, 1316, 1315, 840, 69, 0, 1318, 1317, 0, 1320, 1319, 1216, 0, 1324, 0, 422, 0, 1331, 20, 0, 1332, 465, 0, 0, 204, 0, 0, 0, 169, 0, 0, 0, 841, 0, 67, 0, 1175, 1178, 0, 0, 67, 0, 810, 985, 0, 205, 220, 0, 1349, 0, 0, 0, 1356, 7, 104, 7, 7, 0, 7, 842, 1365, 170, 781, 1376, 677, 843, 230, 365, 0, 0, 0, 968, 844, 0, 845, 0, 0, 69, 171, 461, 0, 462, 0, 69, 67, 1519, 846, 233, 1521, 0, 0, 20, 0, 0, 1387, 0, 0, 20, 847, 0, 806, 172, 311, 1016, 316, 0, 681, 0, 325, 848, 0, 0, 391, 394, 0, 0, 0, 759, 1413, 897, 900, 903, 906, 313, 0, 318, 1415, 69, 563, 329, 1418, 7, 0, 543, 0, 0, 1420, 0, 849, 173, 788, 20, 0, 62, 0, 544, 0, 890, 0, 7, 545, 7, 7, 7, 7, 7, 7, 0, 0, 0, 1431, 478, 1571, 0, 0, 1434, 546, 1437, 0, 0, 1126, 1440, 0, 1443, 358, 0, 1445, 0, 1447, 1451, 0, 0, 1330, 1454, 479, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 363, 0, 0, 62, 937, 0, 1248, 0, 608, 609, 480, 1464, 481, 610, 0, 547, 506, 0, 1466, 0, 0, 1471, 1600, 0, 387, 508, 0, 1476, 0, 0, 548, 549, 0, 478, 1157, 1490, 0, 0, 0, 625, 628, 938, 632, 0, 0, 638, 1495, 1497, 1501, 0, 1504, 1616, 1506, 0, 788, 788, 479, 1508, 940, 1509, 611, 0, 1621, 1511, 416, 0, 482, 438, 454, 1514, 464, 0, 1006, 1051, 0, 1517, 612, 480, 1520, 481, 0, 1020, 1024, 7, 7, 424, 0, 1032, 451, 456, 0, 467, 0, 0, 1534, 0, 0, 67, 1094, 613, 751, 0, 1103, 763, 0, 550, 780, 0, 0, 1119, 805, 788, 788, 690, 0, 0, 0, 0, 0, 0, 700, 551, 0, 0, 0, 1559, 0, 0, 0, 1560, 1561, 0, 1562, 482, 0, 483, 712, 0, 0, 0, 69, 0, 1175, 788, 0, 0, 721, 724, 552, 1564, 553, 1569, 67, 1053, 20, 0, 0, 0, 0, 0, 0, 0, 0, 1581, 0, 1306, 0, 0, 0, 1585, 0, 0, 0, 788, 860, 788, 0, 556, 0, 0, 0, 0, 578, 59, 60, 0, 0, 1591, 0, 1321, 1592, 61, 62, 0, 1597, 69, 0, 63, 566, 0, 0, 0, 483, 585, 0, 0, 0, 1493, 1494, 20, 635, 0, 0, 10, 0, 0, 13, 16, 0, 20, 1608, 0, 1609, 64, 516, 0, 519, 522, 0, 526, 0, 636, 1614, 837, 1615, 0, 0, 0, 65, 0, 1617, 0, 1618, 0, 0, 411, 1619, 1620, 0, 59, 60, 0, 1624, 0, 0, 0, 0, 61, 62, 1625, 0, 589, 0, 63, 1218, 0, 0, 594, 0, 0, 0, 597, 0, 0, 601, 0, 605, 608, 609, 10, 0, 132, 610, 0, 139, 140, 141, 142, 0, 64, 0, 703, 143, 144, 145, 146, 706, 0, 0, 709, 0, 0, 0, 715, 65, 0, 0, 0, 0, 718, 0, 788, 704, 10, 10, 10, 0, 707, 729, 1304, 710, 66, 0, 1310, 716, 0, 0, 936, 0, 611, 719, 0, 0, 0, 62, 937, 0, 0, 0, 730, 0, 67, 0, 186, 749, 612, 0, 761, 767, 0, 777, 0, 783, 0, 798, 1045, 808, 0, 1064, 0, 0, 814, 1089, 0, 0, 753, 0, 0, 613, 770, 0, 68, 938, 786, 0, 0, 0, 811, 0, 0, 0, 939, 815, 826, 69, 0, 0, 66, 0, 940, 0, 70, 829, 0, 0, 832, 0, 0, 20, 0, 0, 0, 0, 0, 827, 0, 922, 67, 926, 926, 0, 931, 0, 830, 0, 0, 833, 0, 852, 0, 941, 0, 0, 0, 0, 0, 0, 0, 1395, 1398, 0, 0, 0, 942, 0, 943, 298, 68, 1404, 865, 517, 0, 520, 523, 0, 527, 0, 944, 0, 0, 69, 0, 84, 85, 86, 0, 945, 70, 0, 0, 614, 0, 0, 0, 20, 0, 0, 0, 0, 1546, 87, 88, 89, 0, 0, 0, 946, 590, 1169, 0, 0, 0, 0, 595, 1026, 1426, 1430, 598, 0, 0, 602, 0, 606, 0, 0, 947, 0, 847, 0, 90, 91, 92, 394, 0, 1106, 926, 1110, 1110, 926, 1106, 0, 0, 0, 0, 0, 0, 759, 1460, 0, 0, 10, 0, 0, 0, 0, 1198, 69, 0, 0, 0, 0, 0, 0, 0, 0, 1226, 0, 0, 948, 951, 20, 1235, 0, 0, 62, 1257, 0, 1470, 659, 1474, 980, 0, 0, 0, 1586, 1587, 1485, 0, 660, 0, 965, 0, 0, 0, 661, 10, 10, 0, 662, 0, 0, 983, 663, 0, 426, 0, 0, 0, 0, 664, 0, 665, 0, 427, 354, 0, 0, 1013, 428, 429, 0, 666, 667, 668, 0, 1610, 0, 0, 0, 1037, 0, 0, 1056, 0, 0, 1071, 1080, 430, 1014, 431, 0, 0, 0, 1530, 0, 0, 0, 0, 0, 0, 1047, 0, 0, 1065, 0, 0, 1073, 1090, 0, 0, 0, 926, 506, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1361, 0, 0, 432, 433, 0, 0, 0, 1373, 0, 0, 1380, 0, 434, 435, 10, 0, 0, 0, 0, 0, 0, 0, 0, 10, 279, 0, 0, 280, 0, 0, 0, 281, 282, 283, 284, 1575, 285, 1579, 286, 287, 0, 0, 288, 0, 0, 0, 0, 0, 0, 436, 289, 0, 0, 0, 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 292, 1168, 293, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 1170, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1435, 0, 1438, 0, 0, 0, 1441, 1195, 1444, 0, 1208, 1446, 0, 1448, 0, 0, 0, 1225, 0, 0, 0, 0, 0, 1234, 0, 0, 1240, 1250, 1199, 0, 0, 1215, 0, 0, 1269, 0, 0, 0, 1227, 0, 0, 0, 0, 0, 1237, 0, 0, 1247, 1258, 0, 0, 0, 0, 0, 0, 1273, 532, 533, 534, 535, 536, 537, 539, 540, 541, 542, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1325, 607, 0, 0, 0, 630, 0, 0, 0, 0, 640, 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1543, 0, 0, 0, 0, 0, 0, 1357, 0, 0, 0, 0, 0, 0, 0, 1366, 0, 0, 1377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1364, 0, 0, 0, 0, 0, 0, 0, 1374, 0, 0, 1381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1570, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 10, 10, 0, 10, 0, 0, 0, 1477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1481, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1536, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 1545, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10 }; static const yytype_int16 yycheck[] = { 25, 518, 216, 773, 213, 215, 680, 1003, 673, 476, 199, 923, 677, 39, 39, 1217, 682, 908, 43, 789, 213, 927, 47, 1003, 1113, 927, 927, 909, 53, 1138, 544, 927, 57, 58, 927, 32, 24, 551, 927, 553, 746, 1138, 6, 211, 75, 919, 235, 256, 237, 3, 930, 1299, 930, 4, 934, 4, 934, 939, 930, 269, 924, 935, 934, 934, 946, 6, 3, 3, 93, 3, 4, 5, 6, 98, 3, 4, 5, 6, 246, 3, 746, 1124, 392, 6, 3, 919, 75, 978, 113, 3, 188, 1116, 117, 1393, 66, 4, 121, 4, 122, 773, 125, 935, 127, 6, 3, 130, 131, 3, 133, 134, 135, 3, 176, 71, 148, 4, 3, 3, 1450, 4, 86, 238, 147, 196, 149, 72, 178, 930, 255, 117, 104, 934, 157, 1015, 1076, 257, 226, 651, 228, 653, 654, 655, 219, 131, 111, 775, 219, 19, 4, 0, 1450, 236, 4, 272, 179, 3, 185, 116, 1100, 236, 32, 867, 154, 236, 156, 795, 845, 242, 295, 284, 195, 286, 236, 295, 199, 67, 295, 143, 295, 3, 265, 139, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 1524, 167, 1396, 241, 1423, 295, 149, 150, 1427, 265, 61, 104, 1229, 295, 115, 131, 115, 398, 235, 89, 237, 242, 888, 162, 241, 1097, 295, 89, 295, 89, 295, 888, 1524, 1097, 115, 181, 216, 217, 115, 73, 131, 187, 170, 934, 224, 1117, 1116, 1117, 194, 144, 273, 295, 1116, 1117, 1117, 89, 1120, 295, 187, 187, 286, 278, 141, 141, 115, 99, 3, 115, 89, 927, 941, 187, 295, 944, 167, 181, 187, 241, 295, 295, 140, 187, 1156, 89, 301, 1111, 303, 93, 4, 1483, 307, 170, 273, 181, 173, 173, 187, 599, 199, 187, 201, 259, 201, 187, 1160, 182, 183, 184, 187, 187, 161, 1412, 330, 330, 332, 332, 334, 334, 1184, 336, 337, 1116, 1411, 1563, 342, 342, 344, 344, 261, 245, 236, 295, 349, 197, 1217, 352, 295, 295, 1532, 295, 320, 321, 322, 1105, 545, 260, 261, 187, 236, 295, 367, 552, 295, 3, 295, 250, 1391, 1229, 1375, 1229, 1232, 245, 1232, 214, 1, 1229, 295, 295, 5, 295, 89, 192, 17, 194, 295, 392, 1248, 1458, 395, 396, 295, 398, 1576, 543, 29, 30, 403, 247, 405, 295, 407, 1265, 1266, 410, 295, 1052, 1067, 42, 121, 115, 295, 390, 295, 237, 238, 245, 257, 89, 148, 1275, 55, 1399, 1513, 264, 59, 60, 295, 295, 295, 281, 65, 66, 402, 68, 1513, 295, 1117, 1399, 276, 277, 67, 118, 238, 295, 126, 295, 338, 64, 302, 1321, 71, 72, 117, 460, 181, 76, 157, 281, 1322, 1323, 187, 6, 258, 295, 471, 82, 1322, 1323, 475, 109, 281, 295, 89, 90, 101, 102, 103, 112, 184, 114, 487, 1572, 4, 161, 295, 281, 378, 86, 158, 1467, 1354, 126, 132, 1572, 160, 205, 131, 338, 505, 295, 479, 672, 123, 510, 206, 1467, 233, 514, 515, 236, 127, 77, 78, 153, 521, 155, 89, 524, 139, 241, 1384, 528, 1386, 1396, 122, 160, 84, 144, 1384, 63, 1386, 538, 233, 1221, 77, 236, 390, 378, 210, 267, 547, 162, 159, 384, 385, 4, 83, 187, 89, 82, 3, 530, 89, 266, 270, 89, 89, 90, 164, 194, 126, 200, 758, 1457, 65, 295, 238, 408, 409, 209, 1458, 85, 281, 1221, 1458, 1458, 1554, 212, 1027, 586, 1458, 180, 295, 1458, 591, 294, 295, 1458, 89, 224, 225, 292, 1554, 275, 295, 212, 169, 604, 215, 790, 1352, 174, 136, 1475, 239, 203, 282, 279, 148, 130, 1483, 144, 619, 151, 231, 790, 251, 624, 279, 1275, 627, 238, 239, 295, 631, 479, 89, 287, 150, 68, 637, 70, 148, 254, 168, 74, 236, 194, 278, 646, 647, 648, 1138, 650, 651, 179, 653, 654, 655, 656, 657, 658, 94, 89, 194, 188, 115, 190, 1522, 1532, 259, 62, 669, 930, 281, 672, 1522, 934, 675, 676, 221, 678, 106, 680, 295, 682, 530, 684, 295, 212, 687, 308, 689, 104, 319, 692, 693, 138, 89, 125, 697, 698, 699, 129, 701, 256, 166, 238, 231, 100, 101, 102, 103, 1576, 711, 148, 1353, 108, 281, 275, 274, 62, 89, 720, 177, 243, 723, 258, 95, 726, 727, 258, 295, 269, 183, 184, 353, 354, 181, 295, 284, 366, 286, 234, 187, 264, 98, 62, 89, 746, 281, 295, 89, 157, 281, 165, 286, 281, 281, 100, 101, 102, 103, 1505, 295, 26, 27, 108, 295, 110, 89, 295, 295, 157, 89, 400, 114, 608, 609, 40, 611, 612, 613, 64, 122, 100, 101, 102, 103, 108, 281, 233, 233, 108, 220, 236, 89, 90, 758, 290, 97, 82, 95, 236, 295, 224, 127, 988, 89, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 1458, 122, 819, 988, 191, 89, 114, 253, 281, 673, 178, 158, 89, 677, 127, 452, 248, 681, 229, 166, 1097, 249, 295, 89, 461, 470, 127, 238, 286, 233, 107, 144, 236, 286, 295, 281, 89, 482, 105, 1116, 1097, 610, 695, 144, 237, 203, 87, 124, 89, 295, 867, 238, 82, 137, 871, 1131, 873, 272, 1134, 89, 90, 878, 879, 23, 211, 882, 511, 884, 229, 1075, 392, 888, 113, 392, 891, 188, 893, 238, 191, 896, 89, 238, 899, 136, 295, 902, 163, 970, 905, 49, 754, 295, 909, 1095, 229, 55, 913, 127, 915, 238, 1449, 918, 919, 238, 392, 1411, 1412, 924, 295, 89, 927, 9, 1, 930, 144, 168, 933, 934, 935, 280, 281, 1229, 1205, 280, 281, 238, 179, 392, 108, 159, 89, 395, 271, 217, 295, 938, 34, 238, 295, 938, 791, 792, 793, 794, 392, 280, 281, 610, 224, 47, 967, 1513, 533, 534, 179, 536, 295, 945, 539, 976, 295, 3, 774, 204, 89, 212, 695, 947, 281, 103, 1143, 1391, 238, 990, 199, 216, 1482, 1068, 67, 1391, 281, 258, 295, 1116, 225, 215, 1003, 146, 1190, 148, 213, 1008, 676, 1010, 295, 1229, 1275, 281, 1200, 1201, 1276, 231, 243, 1279, 281, 869, 943, 1513, 238, 239, 251, 295, 101, 102, 103, 281, 241, 1034, 295, 888, 145, 230, 147, 842, 888, 20, 607, 236, 281, 295, 1524, 222, 223, 1050, 214, 214, 1279, 89, 1590, 1613, 281, 1116, 295, 89, 90, 909, 1555, 934, 20, 630, 241, 281, 232, 215, 295, 50, 392, 1204, 238, 640, 641, 1166, 57, 1264, 189, 295, 1572, 69, 193, 1166, 1275, 755, 281, 726, 176, 939, 57, 58, 50, 1096, 1097, 127, 946, 1100, 1120, 57, 295, 89, 867, 773, 1107, 271, 272, 195, 1449, 1075, 1113, 216, 58, 1116, 1117, 281, 227, 1120, 295, 789, 108, 1124, 77, 1296, 235, 1128, 392, 201, 1131, 295, 1294, 1134, 1135, 369, 1353, 940, 281, 942, 943, 1352, 945, 392, 170, 774, 919, 173, 1149, 1335, 236, 1152, 295, -1, 1155, 1156, 1120, 1158, -1, 1160, -1, 187, 727, 1164, -1, 1166, -1, 1015, -1, 1171, 1171, 157, 281, -1, 1176, 1176, -1, 1179, 1179, 265, -1, 1182, -1, 392, -1, 1186, 295, -1, 1189, 398, -1, -1, 157, -1, -1, -1, 149, -1, -1, -1, 186, -1, 238, -1, 1052, 1053, -1, -1, 238, -1, 684, 879, -1, 157, 179, -1, 1217, -1, -1, -1, 1221, 842, 258, 844, 845, -1, 847, 213, 1229, 182, 192, 1232, 194, 219, 199, 308, -1, -1, -1, 868, 226, -1, 228, -1, -1, 281, 199, 283, -1, 285, -1, 281, 238, 1439, 240, 199, 1442, -1, -1, 295, -1, -1, 1263, -1, -1, 295, 252, -1, 230, 222, 235, 233, 237, -1, 236, -1, 241, 263, -1, -1, 353, 354, -1, -1, -1, 271, 1287, 791, 792, 793, 794, 235, -1, 237, 1295, 281, 505, 241, 1299, 920, -1, 79, -1, -1, 1305, -1, 292, 260, 1156, 295, -1, 89, -1, 91, -1, 789, -1, 938, 96, 940, 941, 942, 943, 944, 945, -1, -1, -1, 1329, 109, 1516, -1, -1, 1334, 112, 1336, -1, -1, 967, 1340, -1, 1342, 307, -1, 1345, -1, 1347, 1348, -1, -1, 1185, 1352, 132, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 307, -1, -1, 89, 90, -1, 92, -1, 71, 72, 153, 1375, 155, 76, -1, 156, 452, -1, 1382, -1, -1, 1385, 1571, -1, 352, 461, -1, 1391, -1, -1, 171, 172, -1, 109, 1026, 1399, -1, -1, -1, 533, 534, 127, 536, -1, -1, 539, 1410, 1411, 1412, -1, 1414, 1600, 1416, -1, 1265, 1266, 132, 1421, 144, 1423, 123, -1, 1611, 1427, 392, -1, 209, 395, 396, 1433, 398, -1, 909, 159, -1, 1439, 139, 153, 1442, 155, -1, 918, 919, 1067, 1068, 392, -1, 924, 395, 396, -1, 398, -1, -1, 1458, -1, -1, 238, 935, 162, 672, -1, 939, 675, -1, 246, 678, -1, -1, 946, 682, 1322, 1323, 607, -1, -1, -1, -1, -1, -1, 614, 262, -1, -1, -1, 1489, -1, -1, -1, 1493, 1494, -1, 1496, 209, -1, 278, 630, -1, -1, -1, 281, -1, 1353, 1354, -1, -1, 640, 641, 289, 1513, 291, 1515, 238, 239, 295, -1, -1, -1, -1, -1, -1, -1, -1, 1527, -1, 1157, -1, -1, -1, 1533, -1, -1, -1, 1384, 746, 1386, -1, 505, -1, -1, -1, -1, 510, 80, 81, -1, -1, 1551, -1, 1181, 1554, 88, 89, -1, 1558, 281, -1, 94, 505, -1, -1, -1, 278, 510, -1, -1, -1, 1405, 1406, 295, 538, -1, -1, 1, -1, -1, 4, 5, -1, 295, 1584, -1, 1586, 120, 478, -1, 480, 481, -1, 483, -1, 538, 1596, 727, 1598, -1, -1, -1, 135, -1, 1604, -1, 1606, -1, -1, 142, 1610, 1611, -1, 80, 81, -1, 1616, -1, -1, -1, -1, 88, 89, 1623, -1, 515, -1, 94, 1101, -1, -1, 521, -1, -1, -1, 525, -1, -1, 528, -1, 530, 71, 72, 67, -1, 69, 76, -1, 35, 36, 37, 38, -1, 120, -1, 619, 43, 44, 45, 46, 624, -1, -1, 627, -1, -1, -1, 631, 135, -1, -1, -1, -1, 637, -1, 1522, 619, 101, 102, 103, -1, 624, 646, 1156, 627, 218, -1, 1160, 631, -1, -1, 82, -1, 123, 637, -1, -1, -1, 89, 90, -1, -1, -1, 646, -1, 238, -1, 131, 672, 139, -1, 675, 676, -1, 678, -1, 680, -1, 682, 927, 684, -1, 930, -1, -1, 689, 934, -1, -1, 672, -1, -1, 162, 676, -1, 268, 127, 680, -1, -1, -1, 684, -1, -1, -1, 136, 689, 711, 281, -1, -1, 218, -1, 144, -1, 288, 720, -1, -1, 723, -1, -1, 295, -1, -1, -1, -1, -1, 711, -1, 842, 238, 844, 845, -1, 847, -1, 720, -1, -1, 723, -1, 746, -1, 175, -1, -1, -1, -1, -1, -1, -1, 1265, 1266, -1, -1, -1, 188, -1, 190, 224, 268, 1275, 746, 478, -1, 480, 481, -1, 483, -1, 202, -1, -1, 281, -1, 11, 12, 13, -1, 211, 288, -1, -1, 254, -1, -1, -1, 295, -1, -1, -1, -1, 1461, 29, 30, 31, -1, -1, -1, 231, 515, 1050, -1, -1, -1, -1, 521, 920, 1322, 1323, 525, -1, -1, 528, -1, 530, -1, -1, 250, -1, 252, -1, 58, 59, 60, 938, -1, 940, 941, 942, 943, 944, 945, -1, -1, -1, -1, -1, -1, 271, 1354, -1, -1, 308, -1, -1, -1, -1, 1097, 281, -1, -1, -1, -1, -1, -1, -1, -1, 1107, -1, -1, 293, 867, 295, 1113, -1, -1, 89, 1117, -1, 1384, 8, 1386, 878, -1, -1, -1, 1546, 1547, 1393, -1, 18, -1, 867, -1, -1, -1, 24, 353, 354, -1, 28, -1, -1, 878, 32, -1, 119, -1, -1, -1, -1, 39, -1, 41, -1, 128, 129, -1, -1, 915, 133, 134, -1, 51, 52, 53, -1, 1587, -1, -1, -1, 927, -1, -1, 930, -1, -1, 933, 934, 152, 915, 154, -1, -1, -1, 1450, -1, -1, -1, -1, -1, -1, 927, -1, -1, 930, -1, -1, 933, 934, -1, -1, -1, 1067, 1068, -1, -1, -1, -1, -1, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 1221, -1, -1, 197, 198, -1, -1, -1, 1229, -1, -1, 1232, -1, 207, 208, 452, -1, -1, -1, -1, -1, -1, -1, -1, 461, 7, -1, -1, 10, -1, -1, -1, 14, 15, 16, 17, 1522, 19, 1524, 21, 22, -1, -1, 25, -1, -1, -1, -1, -1, -1, 244, 33, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, 54, 1050, 56, -1, -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, -1, 281, -1, -1, -1, -1, -1, -1, 1050, -1, -1, -1, -1, -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1334, -1, 1336, -1, -1, -1, 1340, 1097, 1342, -1, 1100, 1345, -1, 1347, -1, -1, -1, 1107, -1, -1, -1, -1, -1, 1113, -1, -1, 1116, 1117, 1097, -1, -1, 1100, -1, -1, 1124, -1, -1, -1, 1107, -1, -1, -1, -1, -1, 1113, -1, -1, 1116, 1117, -1, -1, -1, -1, -1, -1, 1124, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1182, 531, -1, -1, -1, 535, -1, -1, -1, -1, 540, 541, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1182, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1458, -1, -1, -1, -1, -1, -1, 1221, -1, -1, -1, -1, -1, -1, -1, 1229, -1, -1, 1232, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1221, -1, -1, -1, -1, -1, -1, -1, 1229, -1, -1, 1232, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1515, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 842, -1, 844, 845, -1, 847, -1, -1, -1, 1391, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1391, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1458, -1, 920, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 938, 1458, 940, 941, 942, 943, 944, 945, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1051, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1067, 1068 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint16 yystos[] = { 0, 116, 298, 3, 187, 245, 300, 549, 551, 663, 764, 0, 550, 764, 549, 664, 764, 118, 302, 111, 295, 297, 395, 6, 261, 665, 695, 765, 4, 766, 117, 301, 131, 396, 423, 426, 549, 552, 764, 698, 765, 297, 766, 766, 161, 488, 423, 427, 158, 397, 483, 297, 395, 766, 297, 160, 487, 489, 299, 80, 81, 88, 89, 94, 120, 135, 218, 238, 268, 281, 288, 297, 333, 334, 349, 350, 359, 407, 439, 609, 650, 711, 737, 754, 11, 12, 13, 29, 30, 31, 58, 59, 60, 484, 205, 398, 587, 297, 766, 297, 350, 107, 124, 163, 258, 297, 350, 384, 416, 495, 690, 737, 766, 766, 115, 670, 766, 351, 20, 50, 57, 360, 20, 50, 57, 408, 766, 766, 551, 652, 766, 738, 764, 126, 275, 332, 419, 728, 297, 35, 36, 37, 38, 43, 44, 45, 46, 588, 206, 399, 589, 297, 388, 551, 493, 551, 493, 691, 766, 297, 766, 670, 297, 765, 297, 297, 766, 297, 77, 149, 182, 199, 222, 260, 327, 468, 538, 576, 614, 651, 696, 729, 297, 5, 297, 445, 764, 765, 766, 767, 297, 297, 297, 297, 241, 620, 297, 84, 339, 385, 301, 301, 294, 297, 350, 737, 762, 327, 766, 670, 327, 328, 469, 539, 577, 615, 697, 210, 279, 297, 350, 596, 650, 734, 446, 766, 297, 341, 552, 297, 350, 650, 690, 737, 267, 417, 709, 496, 709, 270, 715, 763, 297, 297, 297, 297, 78, 297, 327, 329, 332, 150, 297, 466, 468, 766, 183, 184, 297, 538, 540, 542, 543, 670, 201, 297, 576, 578, 670, 223, 297, 614, 616, 620, 297, 695, 696, 765, 765, 7, 10, 14, 15, 16, 17, 19, 21, 22, 25, 33, 42, 48, 54, 56, 61, 735, 295, 445, 764, 765, 766, 766, 164, 340, 497, 200, 580, 710, 83, 297, 336, 350, 690, 737, 297, 336, 350, 690, 737, 766, 73, 99, 237, 297, 320, 350, 368, 646, 650, 737, 330, 332, 467, 766, 541, 542, 276, 277, 544, 670, 730, 731, 579, 670, 617, 620, 297, 297, 297, 494, 552, 297, 581, 125, 129, 220, 253, 297, 350, 389, 418, 420, 680, 737, 338, 551, 766, 765, 765, 765, 297, 395, 297, 395, 297, 395, 297, 297, 544, 297, 395, 297, 395, 297, 140, 247, 297, 350, 449, 669, 491, 551, 421, 422, 551, 390, 681, 85, 337, 342, 766, 297, 282, 369, 741, 647, 741, 544, 670, 670, 423, 142, 297, 333, 334, 349, 350, 359, 407, 439, 451, 609, 650, 711, 737, 754, 119, 128, 133, 134, 152, 154, 197, 198, 207, 208, 244, 297, 350, 405, 420, 432, 435, 437, 472, 476, 572, 574, 590, 592, 661, 737, 177, 297, 350, 526, 737, 23, 49, 55, 343, 283, 285, 297, 350, 650, 690, 737, 742, 746, 766, 765, 297, 297, 297, 670, 670, 297, 109, 132, 153, 155, 209, 278, 391, 428, 434, 452, 474, 478, 594, 732, 551, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 516, 527, 551, 297, 551, 748, 747, 766, 297, 297, 734, 392, 428, 434, 423, 428, 434, 475, 428, 434, 479, 766, 428, 434, 733, 297, 130, 424, 424, 424, 424, 424, 424, 424, 573, 424, 424, 424, 424, 79, 91, 96, 112, 156, 171, 172, 246, 262, 289, 291, 297, 331, 350, 354, 363, 400, 480, 512, 514, 650, 666, 699, 737, 755, 757, 287, 752, 145, 147, 189, 193, 227, 235, 297, 350, 458, 462, 555, 563, 625, 640, 737, 766, 297, 297, 428, 434, 429, 497, 297, 428, 434, 297, 428, 434, 595, 297, 428, 434, 423, 425, 428, 434, 424, 71, 72, 76, 123, 139, 162, 254, 318, 319, 324, 415, 433, 448, 492, 656, 682, 436, 656, 682, 438, 656, 682, 424, 477, 656, 682, 297, 350, 737, 575, 656, 682, 424, 424, 185, 242, 545, 657, 662, 332, 517, 552, 542, 401, 297, 513, 515, 667, 517, 542, 517, 8, 18, 24, 28, 32, 39, 41, 51, 52, 53, 753, 151, 470, 743, 148, 456, 459, 463, 194, 556, 567, 564, 236, 626, 644, 641, 297, 297, 359, 297, 406, 656, 682, 670, 670, 318, 325, 448, 670, 670, 670, 656, 683, 297, 350, 737, 297, 350, 737, 297, 350, 737, 473, 656, 682, 297, 350, 737, 297, 350, 737, 591, 656, 682, 593, 656, 682, 546, 658, 297, 350, 737, 297, 297, 297, 297, 517, 297, 517, 297, 517, 297, 517, 297, 297, 297, 297, 471, 93, 297, 350, 355, 650, 690, 737, 181, 465, 536, 552, 108, 271, 297, 350, 386, 650, 716, 146, 297, 350, 456, 460, 737, 536, 552, 566, 95, 191, 297, 350, 361, 559, 650, 192, 297, 350, 561, 567, 737, 536, 552, 643, 62, 100, 101, 102, 103, 229, 297, 303, 350, 370, 372, 374, 376, 386, 629, 650, 230, 297, 350, 631, 644, 737, 297, 297, 350, 737, 297, 297, 319, 326, 492, 297, 297, 297, 297, 297, 350, 737, 297, 350, 737, 297, 350, 737, 297, 657, 297, 656, 682, 69, 157, 186, 213, 219, 226, 228, 240, 252, 263, 292, 297, 315, 350, 386, 481, 547, 602, 610, 623, 627, 650, 654, 678, 700, 716, 737, 758, 356, 552, 286, 456, 457, 750, 387, 695, 765, 106, 382, 717, 461, 456, 567, 568, 750, 362, 466, 766, 382, 562, 456, 644, 645, 750, 304, 540, 542, 371, 578, 670, 373, 578, 670, 375, 578, 670, 377, 578, 670, 382, 632, 297, 68, 70, 74, 314, 316, 317, 321, 482, 548, 67, 312, 551, 739, 611, 312, 551, 624, 642, 642, 655, 551, 677, 679, 701, 759, 82, 90, 127, 136, 144, 175, 188, 190, 202, 211, 231, 250, 293, 297, 335, 350, 352, 430, 440, 454, 522, 553, 557, 582, 597, 633, 673, 678, 716, 737, 760, 537, 766, 552, 749, 297, 297, 9, 34, 47, 383, 137, 217, 297, 350, 443, 607, 737, 297, 456, 297, 297, 104, 378, 560, 297, 566, 567, 297, 297, 297, 297, 297, 297, 167, 378, 502, 630, 297, 643, 644, 221, 612, 256, 686, 297, 297, 350, 737, 138, 233, 297, 447, 637, 644, 297, 481, 637, 644, 758, 551, 729, 196, 297, 570, 610, 644, 110, 280, 297, 303, 350, 370, 372, 374, 376, 386, 393, 629, 650, 736, 737, 166, 500, 628, 159, 215, 239, 297, 335, 350, 352, 430, 454, 485, 600, 633, 648, 650, 737, 65, 234, 290, 297, 309, 350, 639, 737, 756, 64, 212, 297, 307, 335, 350, 352, 430, 454, 485, 599, 600, 633, 648, 650, 737, 297, 481, 637, 644, 243, 659, 353, 422, 426, 431, 441, 643, 644, 312, 464, 551, 523, 642, 312, 551, 565, 565, 583, 642, 464, 598, 634, 643, 644, 674, 765, 274, 726, 761, 297, 766, 339, 751, 297, 269, 444, 712, 378, 608, 379, 540, 542, 75, 273, 297, 322, 724, 503, 540, 542, 297, 322, 724, 613, 297, 264, 687, 702, 297, 643, 638, 766, 603, 734, 571, 26, 27, 40, 394, 297, 501, 297, 350, 650, 737, 486, 490, 764, 536, 552, 601, 740, 552, 649, 653, 98, 310, 366, 642, 516, 308, 695, 765, 659, 620, 297, 297, 307, 335, 350, 430, 454, 650, 737, 87, 113, 204, 216, 225, 251, 297, 347, 350, 402, 585, 605, 621, 659, 675, 737, 265, 442, 644, 704, 284, 455, 744, 750, 297, 350, 650, 737, 481, 554, 165, 498, 558, 297, 350, 650, 736, 737, 297, 335, 350, 352, 454, 553, 557, 599, 633, 737, 92, 297, 350, 352, 357, 430, 454, 485, 648, 650, 737, 297, 454, 673, 765, 727, 63, 168, 179, 297, 305, 350, 440, 504, 530, 737, 297, 122, 203, 413, 584, 713, 297, 413, 297, 413, 297, 170, 173, 323, 510, 517, 518, 510, 517, 518, 725, 503, 257, 297, 688, 703, 297, 297, 297, 643, 644, 313, 766, 297, 297, 610, 644, 297, 297, 623, 627, 297, 395, 297, 395, 297, 395, 766, 169, 174, 297, 350, 508, 520, 737, 637, 670, 297, 297, 620, 660, 620, 403, 620, 97, 364, 586, 224, 606, 618, 618, 622, 364, 676, 705, 297, 378, 502, 745, 214, 232, 272, 297, 350, 386, 604, 635, 650, 716, 718, 737, 297, 350, 352, 361, 430, 454, 553, 559, 650, 737, 499, 297, 350, 352, 430, 650, 737, 358, 430, 86, 143, 259, 297, 344, 453, 692, 306, 542, 505, 643, 644, 531, 643, 644, 414, 561, 567, 631, 637, 644, 413, 114, 404, 413, 584, 714, 511, 519, 297, 725, 297, 689, 702, 297, 718, 297, 367, 404, 509, 637, 643, 644, 521, 637, 643, 644, 297, 178, 528, 297, 650, 620, 297, 650, 365, 297, 650, 619, 297, 650, 297, 650, 297, 650, 121, 266, 297, 409, 706, 297, 744, 750, 740, 636, 643, 644, 248, 671, 719, 297, 553, 297, 345, 637, 643, 644, 297, 637, 643, 644, 693, 297, 350, 440, 504, 530, 737, 176, 506, 524, 644, 704, 378, 502, 532, 297, 322, 724, 670, 670, 297, 141, 297, 450, 517, 518, 297, 510, 517, 297, 255, 297, 684, 297, 297, 528, 297, 528, 529, 297, 348, 66, 297, 311, 620, 297, 620, 180, 344, 410, 533, 692, 195, 524, 569, 644, 704, 707, 729, 297, 303, 350, 370, 372, 374, 376, 386, 629, 650, 736, 737, 766, 249, 672, 720, 322, 346, 724, 404, 694, 517, 378, 502, 507, 297, 297, 297, 297, 750, 297, 450, 510, 517, 518, 297, 650, 620, 534, 637, 643, 644, 411, 524, 569, 644, 704, 297, 378, 502, 708, 297, 766, 766, 105, 380, 721, 297, 297, 322, 724, 497, 525, 297, 685, 718, 620, 510, 517, 518, 535, 378, 412, 502, 297, 297, 766, 381, 587, 722, 297, 297, 620, 297, 297, 297, 297, 620, 589, 723, 297, 297 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ (Loc).last_line, (Loc).last_column) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into YYRESULT an error message about the unexpected token YYCHAR while in state YYSTATE. Return the number of bytes copied, including the terminating null byte. If YYRESULT is null, do not copy anything; just return the number of bytes that would be copied. As a special case, return 0 if an ordinary "syntax error" message will do. Return YYSIZE_MAXIMUM if overflow occurs during size calculation. */ static YYSIZE_T yysyntax_error (char *yyresult, int yystate, int yychar) { int yyn = yypact[yystate]; if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) return 0; else { int yytype = YYTRANSLATE (yychar); YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; int yysize_overflow = 0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; int yyx; # if 0 /* This is so xgettext sees the translatable formats that are constructed on the fly. */ YY_("syntax error, unexpected %s"); YY_("syntax error, unexpected %s, expecting %s"); YY_("syntax error, unexpected %s, expecting %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); # endif char *yyfmt; char const *yyf; static char const yyunexpected[] = "syntax error, unexpected %s"; static char const yyexpecting[] = ", expecting %s"; static char const yyor[] = " or %s"; char yyformat[sizeof yyunexpected + sizeof yyexpecting - 1 + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) * (sizeof yyor - 1))]; char const *yyprefix = yyexpecting; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 1; yyarg[0] = yytname[yytype]; yyfmt = yystpcpy (yyformat, yyunexpected); for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; yyformat[sizeof yyunexpected - 1] = '\0'; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; yyfmt = yystpcpy (yyfmt, yyprefix); yyprefix = yyor; } yyf = YY_(yyformat); yysize1 = yysize + yystrlen (yyf); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; if (yysize_overflow) return YYSIZE_MAXIMUM; if (yyresult) { /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ char *yyp = yyresult; int yyi = 0; while ((*yyp = *yyf) != '\0') { if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyf += 2; } else { yyp++; yyf++; } } } return yysize; } } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*-------------------------. | yyparse or yypush_parse. | `-------------------------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yytoken = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* Line 1455 of yacc.c */ #line 505 "edif.y" { PopC(); } break; case 11: /* Line 1455 of yacc.c */ #line 520 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 12: /* Line 1455 of yacc.c */ #line 523 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 13: /* Line 1455 of yacc.c */ #line 527 "edif.y" { free((yyvsp[(2) - (5)].s)); free((yyvsp[(3) - (5)].s)); free((yyvsp[(4) - (5)].s)); } break; case 25: /* Line 1455 of yacc.c */ #line 551 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 34: /* Line 1455 of yacc.c */ #line 568 "edif.y" { str_pair_free((yyvsp[(2) - (5)].ps)); free((yyvsp[(3) - (5)].s)); } break; case 36: /* Line 1455 of yacc.c */ #line 572 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 47: /* Line 1455 of yacc.c */ #line 597 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 69: /* Line 1455 of yacc.c */ #line 645 "edif.y" { free((yyvsp[(2) - (5)].s)); free((yyvsp[(3) - (5)].s)); } break; case 70: /* Line 1455 of yacc.c */ #line 648 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 80: /* Line 1455 of yacc.c */ #line 666 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 84: /* Line 1455 of yacc.c */ #line 676 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 91: /* Line 1455 of yacc.c */ #line 691 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 102: /* Line 1455 of yacc.c */ #line 714 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 140: /* Line 1455 of yacc.c */ #line 774 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 147: /* Line 1455 of yacc.c */ #line 789 "edif.y" { free((yyvsp[(2) - (4)].s)); } break; case 150: /* Line 1455 of yacc.c */ #line 796 "edif.y" { free((yyvsp[(2) - (4)].s)); } break; case 182: /* Line 1455 of yacc.c */ #line 866 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 184: /* Line 1455 of yacc.c */ #line 870 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 240: /* Line 1455 of yacc.c */ #line 974 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 247: /* Line 1455 of yacc.c */ #line 987 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 278: /* Line 1455 of yacc.c */ #line 1034 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 279: /* Line 1455 of yacc.c */ #line 1037 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 333: /* Line 1455 of yacc.c */ #line 1123 "edif.y" { free((yyvsp[(2) - (5)].s)); free((yyvsp[(3) - (5)].s)); } break; case 336: /* Line 1455 of yacc.c */ #line 1130 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 337: /* Line 1455 of yacc.c */ #line 1133 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 344: /* Line 1455 of yacc.c */ #line 1146 "edif.y" { free((yyvsp[(1) - (3)].s)); } break; case 346: /* Line 1455 of yacc.c */ #line 1150 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 347: /* Line 1455 of yacc.c */ #line 1151 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 348: /* Line 1455 of yacc.c */ #line 1152 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 369: /* Line 1455 of yacc.c */ #line 1193 "edif.y" { (yyval.s)=(yyvsp[(2) - (4)].s); } break; case 371: /* Line 1455 of yacc.c */ #line 1197 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 374: /* Line 1455 of yacc.c */ #line 1204 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 381: /* Line 1455 of yacc.c */ #line 1215 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 384: /* Line 1455 of yacc.c */ #line 1222 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 388: /* Line 1455 of yacc.c */ #line 1228 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 390: /* Line 1455 of yacc.c */ #line 1232 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 393: /* Line 1455 of yacc.c */ #line 1239 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 397: /* Line 1455 of yacc.c */ #line 1247 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 408: /* Line 1455 of yacc.c */ #line 1262 "edif.y" { pair_list_free((yyvsp[(2) - (2)].pl)); } break; case 437: /* Line 1455 of yacc.c */ #line 1312 "edif.y" { (yyval.pl) = new_pair_list((yyvsp[(2) - (3)].ps)); } break; case 438: /* Line 1455 of yacc.c */ #line 1315 "edif.y" { (yyval.ps)=NULL; } break; case 439: /* Line 1455 of yacc.c */ #line 1316 "edif.y" { (yyvsp[(2) - (2)].ps)->next = (yyvsp[(1) - (2)].ps); (yyval.ps) = (yyvsp[(2) - (2)].ps); } break; case 455: /* Line 1455 of yacc.c */ #line 1342 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 459: /* Line 1455 of yacc.c */ #line 1352 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 460: /* Line 1455 of yacc.c */ #line 1355 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 462: /* Line 1455 of yacc.c */ #line 1361 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 463: /* Line 1455 of yacc.c */ #line 1364 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 483: /* Line 1455 of yacc.c */ #line 1406 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 484: /* Line 1455 of yacc.c */ #line 1409 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 492: /* Line 1455 of yacc.c */ #line 1423 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 506: /* Line 1455 of yacc.c */ #line 1451 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 507: /* Line 1455 of yacc.c */ #line 1454 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 514: /* Line 1455 of yacc.c */ #line 1469 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 549: /* Line 1455 of yacc.c */ #line 1524 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 555: /* Line 1455 of yacc.c */ #line 1536 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 560: /* Line 1455 of yacc.c */ #line 1545 "edif.y" { free((yyvsp[(2) - (4)].s)); } break; case 561: /* Line 1455 of yacc.c */ #line 1548 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 562: /* Line 1455 of yacc.c */ #line 1549 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 582: /* Line 1455 of yacc.c */ #line 1591 "edif.y" { str_pair_free((yyvsp[(2) - (2)].ps)); } break; case 585: /* Line 1455 of yacc.c */ #line 1594 "edif.y" { pair_list_free((yyvsp[(2) - (2)].pl)); } break; case 586: /* Line 1455 of yacc.c */ #line 1597 "edif.y" { (yyval.s)=(yyvsp[(2) - (3)].s); } break; case 587: /* Line 1455 of yacc.c */ #line 1600 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 589: /* Line 1455 of yacc.c */ #line 1604 "edif.y" { (yyval.ps) = new_str_pair((yyvsp[(1) - (1)].s),NULL); } break; case 590: /* Line 1455 of yacc.c */ #line 1605 "edif.y" { (yyval.ps) = new_str_pair((yyvsp[(1) - (1)].s),NULL); } break; case 591: /* Line 1455 of yacc.c */ #line 1606 "edif.y" { (yyval.ps)=(yyvsp[(1) - (1)].ps); } break; case 592: /* Line 1455 of yacc.c */ #line 1609 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 593: /* Line 1455 of yacc.c */ #line 1610 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 594: /* Line 1455 of yacc.c */ #line 1613 "edif.y" { define_pcb_net((yyvsp[(2) - (4)].ps), (yyvsp[(3) - (4)].pl)); } break; case 595: /* Line 1455 of yacc.c */ #line 1616 "edif.y" { (yyval.pl)=(yyvsp[(1) - (1)].pl); } break; case 611: /* Line 1455 of yacc.c */ #line 1638 "edif.y" { str_pair_free((yyvsp[(2) - (4)].ps)); } break; case 632: /* Line 1455 of yacc.c */ #line 1675 "edif.y" { (yyval.ps)=(yyvsp[(1) - (1)].ps); } break; case 633: /* Line 1455 of yacc.c */ #line 1676 "edif.y" { (yyval.ps)=NULL; } break; case 634: /* Line 1455 of yacc.c */ #line 1680 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 639: /* Line 1455 of yacc.c */ #line 1689 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 644: /* Line 1455 of yacc.c */ #line 1700 "edif.y" { str_pair_free((yyvsp[(2) - (2)].ps)); } break; case 698: /* Line 1455 of yacc.c */ #line 1802 "edif.y" { free((yyvsp[(2) - (5)].s)); } break; case 701: /* Line 1455 of yacc.c */ #line 1809 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 727: /* Line 1455 of yacc.c */ #line 1861 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 730: /* Line 1455 of yacc.c */ #line 1868 "edif.y" { str_pair_free((yyvsp[(2) - (2)].ps)); } break; case 747: /* Line 1455 of yacc.c */ #line 1903 "edif.y" { free((yyvsp[(2) - (4)].s)); free((yyvsp[(3) - (4)].s)); } break; case 766: /* Line 1455 of yacc.c */ #line 1934 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 789: /* Line 1455 of yacc.c */ #line 1969 "edif.y" { str_pair_free((yyvsp[(2) - (2)].ps)); } break; case 791: /* Line 1455 of yacc.c */ #line 1975 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 803: /* Line 1455 of yacc.c */ #line 1991 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 818: /* Line 1455 of yacc.c */ #line 2010 "edif.y" { str_pair_free((yyvsp[(2) - (2)].ps)); } break; case 823: /* Line 1455 of yacc.c */ #line 2021 "edif.y" { str_pair_free((yyvsp[(2) - (2)].ps)); } break; case 827: /* Line 1455 of yacc.c */ #line 2027 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 829: /* Line 1455 of yacc.c */ #line 2031 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 831: /* Line 1455 of yacc.c */ #line 2036 "edif.y" { if ((yyvsp[(3) - (4)].ps)) { (yyval.ps) = new_str_pair((yyvsp[(3) - (4)].ps)->str1,(yyvsp[(2) - (4)].s)); free((yyvsp[(3) - (4)].ps)); } else { /* handle port with no instance by passing up the chain */ (yyval.ps) = new_str_pair(NULL,(yyvsp[(2) - (4)].s)); } } break; case 832: /* Line 1455 of yacc.c */ #line 2050 "edif.y" { (yyval.ps)=NULL; } break; case 833: /* Line 1455 of yacc.c */ #line 2051 "edif.y" { (yyval.ps)=(yyvsp[(1) - (1)].ps); } break; case 834: /* Line 1455 of yacc.c */ #line 2052 "edif.y" { (yyval.ps) = new_str_pair((yyvsp[(1) - (1)].s),NULL); } break; case 835: /* Line 1455 of yacc.c */ #line 2053 "edif.y" { (yyval.ps)=NULL; } break; case 848: /* Line 1455 of yacc.c */ #line 2080 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 849: /* Line 1455 of yacc.c */ #line 2083 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 881: /* Line 1455 of yacc.c */ #line 2136 "edif.y" { (yyval.ps) = new_str_pair((yyvsp[(2) - (4)].s),(yyvsp[(3) - (4)].s)); } break; case 882: /* Line 1455 of yacc.c */ #line 2139 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 883: /* Line 1455 of yacc.c */ #line 2140 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 884: /* Line 1455 of yacc.c */ #line 2143 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 885: /* Line 1455 of yacc.c */ #line 2144 "edif.y" { (yyval.s)=NULL; } break; case 889: /* Line 1455 of yacc.c */ #line 2154 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 891: /* Line 1455 of yacc.c */ #line 2160 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 892: /* Line 1455 of yacc.c */ #line 2161 "edif.y" { free((yyvsp[(2) - (4)].s)); free((yyvsp[(3) - (4)].s)); } break; case 893: /* Line 1455 of yacc.c */ #line 2164 "edif.y" { free((yyvsp[(2) - (4)].s)); free((yyvsp[(3) - (4)].s)); } break; case 894: /* Line 1455 of yacc.c */ #line 2167 "edif.y" { free((yyvsp[(2) - (4)].s)); free((yyvsp[(3) - (4)].s)); } break; case 896: /* Line 1455 of yacc.c */ #line 2173 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 898: /* Line 1455 of yacc.c */ #line 2175 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 903: /* Line 1455 of yacc.c */ #line 2186 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 935: /* Line 1455 of yacc.c */ #line 2250 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 943: /* Line 1455 of yacc.c */ #line 2266 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 946: /* Line 1455 of yacc.c */ #line 2271 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 973: /* Line 1455 of yacc.c */ #line 2316 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 987: /* Line 1455 of yacc.c */ #line 2338 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 994: /* Line 1455 of yacc.c */ #line 2354 "edif.y" { free((yyvsp[(2) - (8)].s)); free((yyvsp[(3) - (8)].s)); free((yyvsp[(4) - (8)].s)); free((yyvsp[(5) - (8)].s)); free((yyvsp[(6) - (8)].s)); free((yyvsp[(7) - (8)].s)); } break; case 1054: /* Line 1455 of yacc.c */ #line 2461 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 1055: /* Line 1455 of yacc.c */ #line 2462 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 1056: /* Line 1455 of yacc.c */ #line 2463 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 1057: /* Line 1455 of yacc.c */ #line 2464 "edif.y" { free((yyvsp[(2) - (2)].s)); } break; case 1059: /* Line 1455 of yacc.c */ #line 2468 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 1061: /* Line 1455 of yacc.c */ #line 2472 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 1063: /* Line 1455 of yacc.c */ #line 2476 "edif.y" { free((yyvsp[(2) - (3)].s)); } break; case 1085: /* Line 1455 of yacc.c */ #line 2512 "edif.y" { str_pair_free((yyvsp[(1) - (1)].ps)); } break; case 1086: /* Line 1455 of yacc.c */ #line 2515 "edif.y" { free((yyvsp[(1) - (1)].s)); } break; case 1107: /* Line 1455 of yacc.c */ #line 2556 "edif.y" { str_pair_free((yyvsp[(2) - (2)].ps)); } break; case 1109: /* Line 1455 of yacc.c */ #line 2558 "edif.y" { pair_list_free((yyvsp[(2) - (2)].pl)); } break; case 1126: /* Line 1455 of yacc.c */ #line 2585 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 1127: /* Line 1455 of yacc.c */ #line 2588 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 1128: /* Line 1455 of yacc.c */ #line 2591 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; case 1129: /* Line 1455 of yacc.c */ #line 2594 "edif.y" { (yyval.s)=(yyvsp[(1) - (1)].s); } break; /* Line 1455 of yacc.c */ #line 5130 "edif.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) { YYSIZE_T yyalloc = 2 * yysize; if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) yyalloc = YYSTACK_ALLOC_MAXIMUM; if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yyalloc); if (yymsg) yymsg_alloc = yyalloc; else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; } } if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); yyerror (yymsg); } else { yyerror (YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } } #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } *++yyvsp = yylval; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } /* Line 1675 of yacc.c */ #line 2597 "edif.y" /* * xmalloc: * * Garbage function for 'alloca()'. */ char *xmalloc(int siz) { return ((char *)Malloc(siz)); } /* * Token & context carriers: * * These are the linkage pointers for threading this context garbage * for converting identifiers into parser tokens. */ typedef struct TokenCar { struct TokenCar *Next; /* pointer to next carrier */ struct Token *Token; /* associated token */ } TokenCar; typedef struct UsedCar { struct UsedCar *Next; /* pointer to next carrier */ short Code; /* used '%token' value */ } UsedCar; typedef struct ContextCar { struct ContextCar *Next; /* pointer to next carrier */ struct Context *Context; /* associated context */ union { int Single; /* single usage flag (context tree) */ struct UsedCar *Used; /* single used list (context stack) */ } u; } ContextCar; /* * Token definitions: * * This associates the '%token' codings with strings which are to * be free standing tokens. Doesn't have to be in sorted order but the * strings must be in lower case. */ typedef struct Token { char *Name; /* token name */ int Code; /* '%token' value */ struct Token *Next; /* hash table linkage */ } Token; static Token TokenDef[] = { {"angle", EDIF_TOK_ANGLE}, {"behavior", EDIF_TOK_BEHAVIOR}, {"calculated", EDIF_TOK_CALCULATED}, {"capacitance", EDIF_TOK_CAPACITANCE}, {"centercenter", EDIF_TOK_CENTERCENTER}, {"centerleft", EDIF_TOK_CENTERLEFT}, {"centerright", EDIF_TOK_CENTERRIGHT}, {"charge", EDIF_TOK_CHARGE}, {"conductance", EDIF_TOK_CONDUCTANCE}, {"current", EDIF_TOK_CURRENT}, {"distance", EDIF_TOK_DISTANCE}, {"document", EDIF_TOK_DOCUMENT}, {"energy", EDIF_TOK_ENERGY}, {"extend", EDIF_TOK_EXTEND}, {"flux", EDIF_TOK_FLUX}, {"frequency", EDIF_TOK_FREQUENCY}, {"generic", EDIF_TOK_GENERIC}, {"graphic", EDIF_TOK_GRAPHIC}, {"inductance", EDIF_TOK_INDUCTANCE}, {"inout", EDIF_TOK_INOUT}, {"input", EDIF_TOK_INPUT}, {"logicmodel", EDIF_TOK_LOGICMODEL}, {"lowercenter", EDIF_TOK_LOWERCENTER}, {"lowerleft", EDIF_TOK_LOWERLEFT}, {"lowerright", EDIF_TOK_LOWERRIGHT}, {"masklayout", EDIF_TOK_MASKLAYOUT}, {"mass", EDIF_TOK_MASS}, {"measured", EDIF_TOK_MEASURED}, {"mx", EDIF_TOK_MX}, {"mxr90", EDIF_TOK_MXR90}, {"my", EDIF_TOK_MY}, {"myr90", EDIF_TOK_MYR90}, {"netlist", EDIF_TOK_NETLIST}, {"output", EDIF_TOK_OUTPUT}, {"pcblayout", EDIF_TOK_PCBLAYOUT}, {"power", EDIF_TOK_POWER}, {"r0", EDIF_TOK_R0}, {"r180", EDIF_TOK_R180}, {"r270", EDIF_TOK_R270}, {"r90", EDIF_TOK_R90}, {"required", EDIF_TOK_REQUIRED}, {"resistance", EDIF_TOK_RESISTANCE}, {"ripper", EDIF_TOK_RIPPER}, {"round", EDIF_TOK_ROUND}, {"schematic", EDIF_TOK_SCHEMATIC}, {"stranger", EDIF_TOK_STRANGER}, {"symbolic", EDIF_TOK_SYMBOLIC}, {"temperature", EDIF_TOK_TEMPERATURE}, {"tie", EDIF_TOK_TIE}, {"time", EDIF_TOK_TIME}, {"truncate", EDIF_TOK_TRUNCATE}, {"uppercenter", EDIF_TOK_UPPERCENTER}, {"upperleft", EDIF_TOK_UPPERLEFT}, {"upperright", EDIF_TOK_UPPERRIGHT}, {"voltage", EDIF_TOK_VOLTAGE} }; static int TokenDefSize = sizeof(TokenDef) / sizeof(Token); /* * Token enable definitions: * * There is one array for each set of tokens enabled by a * particular context (barf). Another array is used to bind * these arrays to a context. */ static short e_CellType[] = {EDIF_TOK_TIE, EDIF_TOK_RIPPER, EDIF_TOK_GENERIC}; static short e_CornerType[] = {EDIF_TOK_EXTEND, EDIF_TOK_TRUNCATE, EDIF_TOK_ROUND}; static short e_Derivation[] = {EDIF_TOK_CALCULATED, EDIF_TOK_MEASURED, EDIF_TOK_REQUIRED}; static short e_Direction[] = {EDIF_TOK_INPUT, EDIF_TOK_OUTPUT, EDIF_TOK_INOUT}; static short e_EndType[] = {EDIF_TOK_EXTEND, EDIF_TOK_TRUNCATE, EDIF_TOK_ROUND}; static short e_Justify[] = {EDIF_TOK_CENTERCENTER, EDIF_TOK_CENTERLEFT, EDIF_TOK_CENTERRIGHT, EDIF_TOK_LOWERCENTER, EDIF_TOK_LOWERLEFT, EDIF_TOK_LOWERRIGHT, EDIF_TOK_UPPERCENTER, EDIF_TOK_UPPERLEFT, EDIF_TOK_UPPERRIGHT}; static short e_Orientation[] = {EDIF_TOK_R0, EDIF_TOK_R90, EDIF_TOK_R180, EDIF_TOK_R270, EDIF_TOK_MX, EDIF_TOK_MY, EDIF_TOK_MXR90, EDIF_TOK_MYR90}; static short e_Unit[] = {EDIF_TOK_DISTANCE, EDIF_TOK_CAPACITANCE, EDIF_TOK_CURRENT, EDIF_TOK_RESISTANCE, EDIF_TOK_TEMPERATURE, EDIF_TOK_TIME, EDIF_TOK_VOLTAGE, EDIF_TOK_MASS, EDIF_TOK_FREQUENCY, EDIF_TOK_INDUCTANCE, EDIF_TOK_ENERGY, EDIF_TOK_POWER, EDIF_TOK_CHARGE, EDIF_TOK_CONDUCTANCE, EDIF_TOK_FLUX, EDIF_TOK_ANGLE}; static short e_ViewType[] = {EDIF_TOK_MASKLAYOUT, EDIF_TOK_PCBLAYOUT, EDIF_TOK_NETLIST, EDIF_TOK_SCHEMATIC, EDIF_TOK_SYMBOLIC, EDIF_TOK_BEHAVIOR, EDIF_TOK_LOGICMODEL, EDIF_TOK_DOCUMENT, EDIF_TOK_GRAPHIC, EDIF_TOK_STRANGER}; /* * Token tying table: * * This binds enabled tokens to a context. */ typedef struct Tie { short *Enable; /* pointer to enable array */ short Origin; /* '%token' value of context */ short EnableSize; /* size of enabled array */ } Tie; #define TE(e,o) {e,o,sizeof(e)/sizeof(short)} static Tie TieDef[] = { TE(e_CellType, EDIF_TOK_CELLTYPE), TE(e_CornerType, EDIF_TOK_CORNERTYPE), TE(e_Derivation, EDIF_TOK_DERIVATION), TE(e_Direction, EDIF_TOK_DIRECTION), TE(e_EndType, EDIF_TOK_ENDTYPE), TE(e_Justify, EDIF_TOK_JUSTIFY), TE(e_Orientation, EDIF_TOK_ORIENTATION), TE(e_Unit, EDIF_TOK_UNIT), TE(e_ViewType, EDIF_TOK_VIEWTYPE) }; static int TieDefSize = sizeof(TieDef) / sizeof(Tie); /* * Context definitions: * * This associates keyword strings with '%token' values. It * also creates a pretty much empty header for later building of * the context tree. Again they needn't be sorted, but strings * must be lower case. */ typedef struct Context { char *Name; /* keyword name */ short Code; /* '%token' value */ short Flags; /* special operation flags */ struct ContextCar *Context; /* contexts which can be moved to */ struct TokenCar *Token; /* active tokens */ struct Context *Next; /* hash table linkage */ } Context; static Context ContextDef[] = { {"", 0}, /* start context */ {"acload", EDIF_TOK_ACLOAD}, {"after", EDIF_TOK_AFTER}, {"annotate", EDIF_TOK_ANNOTATE}, {"apply", EDIF_TOK_APPLY}, {"arc", EDIF_TOK_ARC}, {"array", EDIF_TOK_ARRAY}, {"arraymacro", EDIF_TOK_ARRAYMACRO}, {"arrayrelatedinfo", EDIF_TOK_ARRAYRELATEDINFO}, {"arraysite", EDIF_TOK_ARRAYSITE}, {"atleast", EDIF_TOK_ATLEAST}, {"atmost", EDIF_TOK_ATMOST}, {"author", EDIF_TOK_AUTHOR}, {"basearray", EDIF_TOK_BASEARRAY}, {"becomes", EDIF_TOK_BECOMES}, {"between", EDIF_TOK_BETWEEN}, {"boolean", EDIF_TOK_BOOLEAN}, {"booleandisplay", EDIF_TOK_BOOLEANDISPLAY}, {"booleanmap", EDIF_TOK_BOOLEANMAP}, {"borderpattern", EDIF_TOK_BORDERPATTERN}, {"borderwidth", EDIF_TOK_BORDERWIDTH}, {"boundingbox", EDIF_TOK_BOUNDINGBOX}, {"cell", EDIF_TOK_CELL}, {"cellref", EDIF_TOK_CELLREF}, {"celltype", EDIF_TOK_CELLTYPE}, {"change", EDIF_TOK_CHANGE}, {"circle", EDIF_TOK_CIRCLE}, {"color", EDIF_TOK_COLOR}, {"comment", EDIF_TOK_COMMENT}, {"commentgraphics", EDIF_TOK_COMMENTGRAPHICS}, {"compound", EDIF_TOK_COMPOUND}, {"connectlocation", EDIF_TOK_CONNECTLOCATION}, {"contents", EDIF_TOK_CONTENTS}, {"cornertype", EDIF_TOK_CORNERTYPE}, {"criticality", EDIF_TOK_CRITICALITY}, {"currentmap", EDIF_TOK_CURRENTMAP}, {"curve", EDIF_TOK_CURVE}, {"cycle", EDIF_TOK_CYCLE}, {"dataorigin", EDIF_TOK_DATAORIGIN}, {"dcfaninload", EDIF_TOK_DCFANINLOAD}, {"dcfanoutload", EDIF_TOK_DCFANOUTLOAD}, {"dcmaxfanin", EDIF_TOK_DCMAXFANIN}, {"dcmaxfanout", EDIF_TOK_DCMAXFANOUT}, {"delay", EDIF_TOK_DELAY}, {"delta", EDIF_TOK_DELTA}, {"derivation", EDIF_TOK_DERIVATION}, {"design", EDIF_TOK_DESIGN}, {"designator", EDIF_TOK_DESIGNATOR}, {"difference", EDIF_TOK_DIFFERENCE}, {"direction", EDIF_TOK_DIRECTION}, {"display", EDIF_TOK_DISPLAY}, {"dominates", EDIF_TOK_DOMINATES}, {"dot", EDIF_TOK_DOT}, {"duration", EDIF_TOK_DURATION}, {"e", EDIF_TOK_E}, {"edif", EDIF_TOK_EDIF}, {"ediflevel", EDIF_TOK_EDIFLEVEL}, {"edifversion", EDIF_TOK_EDIFVERSION}, {"enclosuredistance", EDIF_TOK_ENCLOSUREDISTANCE}, {"endtype", EDIF_TOK_ENDTYPE}, {"entry", EDIF_TOK_ENTRY}, {"exactly", EDIF_TOK_EXACTLY}, {"external", EDIF_TOK_EXTERNAL}, {"fabricate", EDIF_TOK_FABRICATE}, {"false", EDIF_TOK_FALSE}, {"figure", EDIF_TOK_FIGURE}, {"figurearea", EDIF_TOK_FIGUREAREA}, {"figuregroup", EDIF_TOK_FIGUREGROUP}, {"figuregroupobject", EDIF_TOK_FIGUREGROUPOBJECT}, {"figuregroupoverride", EDIF_TOK_FIGUREGROUPOVERRIDE}, {"figuregroupref", EDIF_TOK_FIGUREGROUPREF}, {"figureperimeter", EDIF_TOK_FIGUREPERIMETER}, {"figurewidth", EDIF_TOK_FIGUREWIDTH}, {"fillpattern", EDIF_TOK_FILLPATTERN}, {"follow", EDIF_TOK_FOLLOW}, {"forbiddenevent", EDIF_TOK_FORBIDDENEVENT}, {"globalportref", EDIF_TOK_GLOBALPORTREF}, {"greaterthan", EDIF_TOK_GREATERTHAN}, {"gridmap", EDIF_TOK_GRIDMAP}, {"ignore", EDIF_TOK_IGNORE}, {"includefiguregroup", EDIF_TOK_INCLUDEFIGUREGROUP}, {"initial", EDIF_TOK_INITIAL}, {"instance", EDIF_TOK_INSTANCE}, {"instancebackannotate", EDIF_TOK_INSTANCEBACKANNOTATE}, {"instancegroup", EDIF_TOK_INSTANCEGROUP}, {"instancemap", EDIF_TOK_INSTANCEMAP}, {"instanceref", EDIF_TOK_INSTANCEREF}, {"integer", EDIF_TOK_INTEGER}, {"integerdisplay", EDIF_TOK_INTEGERDISPLAY}, {"interface", EDIF_TOK_INTERFACE}, {"interfiguregroupspacing", EDIF_TOK_INTERFIGUREGROUPSPACING}, {"intersection", EDIF_TOK_INTERSECTION}, {"intrafiguregroupspacing", EDIF_TOK_INTRAFIGUREGROUPSPACING}, {"inverse", EDIF_TOK_INVERSE}, {"isolated", EDIF_TOK_ISOLATED}, {"joined", EDIF_TOK_JOINED}, {"justify", EDIF_TOK_JUSTIFY}, {"keyworddisplay", EDIF_TOK_KEYWORDDISPLAY}, {"keywordlevel", EDIF_TOK_KEYWORDLEVEL}, {"keywordmap", EDIF_TOK_KEYWORDMAP}, {"lessthan", EDIF_TOK_LESSTHAN}, {"library", EDIF_TOK_LIBRARY}, {"libraryref", EDIF_TOK_LIBRARYREF}, {"listofnets", EDIF_TOK_LISTOFNETS}, {"listofports", EDIF_TOK_LISTOFPORTS}, {"loaddelay", EDIF_TOK_LOADDELAY}, {"logicassign", EDIF_TOK_LOGICASSIGN}, {"logicinput", EDIF_TOK_LOGICINPUT}, {"logiclist", EDIF_TOK_LOGICLIST}, {"logicmapinput", EDIF_TOK_LOGICMAPINPUT}, {"logicmapoutput", EDIF_TOK_LOGICMAPOUTPUT}, {"logiconeof", EDIF_TOK_LOGICONEOF}, {"logicoutput", EDIF_TOK_LOGICOUTPUT}, {"logicport", EDIF_TOK_LOGICPORT}, {"logicref", EDIF_TOK_LOGICREF}, {"logicvalue", EDIF_TOK_LOGICVALUE}, {"logicwaveform", EDIF_TOK_LOGICWAVEFORM}, {"maintain", EDIF_TOK_MAINTAIN}, {"match", EDIF_TOK_MATCH}, {"member", EDIF_TOK_MEMBER}, {"minomax", EDIF_TOK_MINOMAX}, {"minomaxdisplay", EDIF_TOK_MINOMAXDISPLAY}, {"mnm", EDIF_TOK_MNM}, {"multiplevalueset", EDIF_TOK_MULTIPLEVALUESET}, {"mustjoin", EDIF_TOK_MUSTJOIN}, {"name", EDIF_TOK_NAME}, {"net", EDIF_TOK_NET}, {"netbackannotate", EDIF_TOK_NETBACKANNOTATE}, {"netbundle", EDIF_TOK_NETBUNDLE}, {"netdelay", EDIF_TOK_NETDELAY}, {"netgroup", EDIF_TOK_NETGROUP}, {"netmap", EDIF_TOK_NETMAP}, {"netref", EDIF_TOK_NETREF}, {"nochange", EDIF_TOK_NOCHANGE}, {"nonpermutable", EDIF_TOK_NONPERMUTABLE}, {"notallowed", EDIF_TOK_NOTALLOWED}, {"notchspacing", EDIF_TOK_NOTCHSPACING}, {"number", EDIF_TOK_NUMBER}, {"numberdefinition", EDIF_TOK_NUMBERDEFINITION}, {"numberdisplay", EDIF_TOK_NUMBERDISPLAY}, {"offpageconnector", EDIF_TOK_OFFPAGECONNECTOR}, {"offsetevent", EDIF_TOK_OFFSETEVENT}, {"openshape", EDIF_TOK_OPENSHAPE}, {"orientation", EDIF_TOK_ORIENTATION}, {"origin", EDIF_TOK_ORIGIN}, {"overhangdistance", EDIF_TOK_OVERHANGDISTANCE}, {"overlapdistance", EDIF_TOK_OVERLAPDISTANCE}, {"oversize", EDIF_TOK_OVERSIZE}, {"owner", EDIF_TOK_OWNER}, {"page", EDIF_TOK_PAGE}, {"pagesize", EDIF_TOK_PAGESIZE}, {"parameter", EDIF_TOK_PARAMETER}, {"parameterassign", EDIF_TOK_PARAMETERASSIGN}, {"parameterdisplay", EDIF_TOK_PARAMETERDISPLAY}, {"path", EDIF_TOK_PATH}, {"pathdelay", EDIF_TOK_PATHDELAY}, {"pathwidth", EDIF_TOK_PATHWIDTH}, {"permutable", EDIF_TOK_PERMUTABLE}, {"physicaldesignrule", EDIF_TOK_PHYSICALDESIGNRULE}, {"plug", EDIF_TOK_PLUG}, {"point", EDIF_TOK_POINT}, {"pointdisplay", EDIF_TOK_POINTDISPLAY}, {"pointlist", EDIF_TOK_POINTLIST}, {"polygon", EDIF_TOK_POLYGON}, {"port", EDIF_TOK_PORT}, {"portbackannotate", EDIF_TOK_PORTBACKANNOTATE}, {"portbundle", EDIF_TOK_PORTBUNDLE}, {"portdelay", EDIF_TOK_PORTDELAY}, {"portgroup", EDIF_TOK_PORTGROUP}, {"portimplementation", EDIF_TOK_PORTIMPLEMENTATION}, {"portinstance", EDIF_TOK_PORTINSTANCE}, {"portlist", EDIF_TOK_PORTLIST}, {"portlistalias", EDIF_TOK_PORTLISTALIAS}, {"portmap", EDIF_TOK_PORTMAP}, {"portref", EDIF_TOK_PORTREF}, {"program", EDIF_TOK_PROGRAM}, {"property", EDIF_TOK_PROPERTY}, {"propertydisplay", EDIF_TOK_PROPERTYDISPLAY}, {"protectionframe", EDIF_TOK_PROTECTIONFRAME}, {"pt", EDIF_TOK_PT}, {"rangevector", EDIF_TOK_RANGEVECTOR}, {"rectangle", EDIF_TOK_RECTANGLE}, {"rectanglesize", EDIF_TOK_RECTANGLESIZE}, {"rename", EDIF_TOK_RENAME}, {"resolves", EDIF_TOK_RESOLVES}, {"scale", EDIF_TOK_SCALE}, {"scalex", EDIF_TOK_SCALEX}, {"scaley", EDIF_TOK_SCALEY}, {"section", EDIF_TOK_SECTION}, {"shape", EDIF_TOK_SHAPE}, {"simulate", EDIF_TOK_SIMULATE}, {"simulationinfo", EDIF_TOK_SIMULATIONINFO}, {"singlevalueset", EDIF_TOK_SINGLEVALUESET}, {"site", EDIF_TOK_SITE}, {"socket", EDIF_TOK_SOCKET}, {"socketset", EDIF_TOK_SOCKETSET}, {"status", EDIF_TOK_STATUS}, {"steady", EDIF_TOK_STEADY}, {"string", EDIF_TOK_STRING}, {"stringdisplay", EDIF_TOK_STRINGDISPLAY}, {"strong", EDIF_TOK_STRONG}, {"symbol", EDIF_TOK_SYMBOL}, {"symmetry", EDIF_TOK_SYMMETRY}, {"table", EDIF_TOK_TABLE}, {"tabledefault", EDIF_TOK_TABLEDEFAULT}, {"technology", EDIF_TOK_TECHNOLOGY}, {"textheight", EDIF_TOK_TEXTHEIGHT}, {"timeinterval", EDIF_TOK_TIMEINTERVAL}, {"timestamp", EDIF_TOK_TIMESTAMP}, {"timing", EDIF_TOK_TIMING}, {"transform", EDIF_TOK_TRANSFORM}, {"transition", EDIF_TOK_TRANSITION}, {"trigger", EDIF_TOK_TRIGGER}, {"true", EDIF_TOK_TRUE}, {"unconstrained", EDIF_TOK_UNCONSTRAINED}, {"undefined", EDIF_TOK_UNDEFINED}, {"union", EDIF_TOK_UNION}, {"unit", EDIF_TOK_UNIT}, {"unused", EDIF_TOK_UNUSED}, {"userdata", EDIF_TOK_USERDATA}, {"version", EDIF_TOK_VERSION}, {"view", EDIF_TOK_VIEW}, {"viewlist", EDIF_TOK_VIEWLIST}, {"viewmap", EDIF_TOK_VIEWMAP}, {"viewref", EDIF_TOK_VIEWREF}, {"viewtype", EDIF_TOK_VIEWTYPE}, {"visible", EDIF_TOK_VISIBLE}, {"voltagemap", EDIF_TOK_VOLTAGEMAP}, {"wavevalue", EDIF_TOK_WAVEVALUE}, {"weak", EDIF_TOK_WEAK}, {"weakjoined", EDIF_TOK_WEAKJOINED}, {"when", EDIF_TOK_WHEN}, {"written", EDIF_TOK_WRITTEN} }; static int ContextDefSize = sizeof(ContextDef) / sizeof(Context); /* * Context follower tables: * * This is pretty ugly, an array is defined for each context * which has following context levels. Yet another table is used * to bind these arrays to the originating contexts. * Arrays are declared as: * * static short f_[] = { ... }; * * The array entries are the '%token' values for all keywords which * can be reached from the context. Like I said, ugly, * but it works. * A negative entry means that the follow can only occur once within * the specified context. */ static short f_NULL[] = {EDIF_TOK_EDIF}; static short f_Edif[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_EDIFVERSION, EDIF_TOK_EDIFLEVEL, EDIF_TOK_KEYWORDMAP, -EDIF_TOK_STATUS, EDIF_TOK_EXTERNAL, EDIF_TOK_LIBRARY, EDIF_TOK_DESIGN, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_AcLoad[] = {EDIF_TOK_MNM, EDIF_TOK_E, EDIF_TOK_MINOMAXDISPLAY}; static short f_After[] = {EDIF_TOK_MNM, EDIF_TOK_E, EDIF_TOK_FOLLOW, EDIF_TOK_MAINTAIN, EDIF_TOK_LOGICASSIGN, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Annotate[] = {EDIF_TOK_STRINGDISPLAY}; static short f_Apply[] = {EDIF_TOK_CYCLE, EDIF_TOK_LOGICINPUT, EDIF_TOK_LOGICOUTPUT, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Arc[] = {EDIF_TOK_PT}; static short f_Array[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME}; static short f_ArrayMacro[] = {EDIF_TOK_PLUG}; static short f_ArrayRelatedInfo[] = {EDIF_TOK_BASEARRAY, EDIF_TOK_ARRAYSITE, EDIF_TOK_ARRAYMACRO, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_ArraySite[] = {EDIF_TOK_SOCKET}; static short f_AtLeast[] = {EDIF_TOK_E}; static short f_AtMost[] = {EDIF_TOK_E}; static short f_Becomes[] = {EDIF_TOK_NAME, EDIF_TOK_LOGICLIST, EDIF_TOK_LOGICONEOF}; /* static short f_Between[] = {EDIF_TOK_ATLEAST, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_LESSTHAN}; */ static short f_Boolean[] = {EDIF_TOK_FALSE, EDIF_TOK_TRUE, EDIF_TOK_BOOLEANDISPLAY, EDIF_TOK_BOOLEAN}; static short f_BooleanDisplay[] = {EDIF_TOK_FALSE, EDIF_TOK_TRUE, EDIF_TOK_DISPLAY}; static short f_BooleanMap[] = {EDIF_TOK_FALSE, EDIF_TOK_TRUE}; static short f_BorderPattern[] = {EDIF_TOK_BOOLEAN}; static short f_BoundingBox[] = {EDIF_TOK_RECTANGLE}; static short f_Cell[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_CELLTYPE, -EDIF_TOK_STATUS, -EDIF_TOK_VIEWMAP, EDIF_TOK_VIEW, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA, EDIF_TOK_PROPERTY}; static short f_CellRef[] = {EDIF_TOK_NAME, EDIF_TOK_LIBRARYREF}; static short f_Change[] = {EDIF_TOK_NAME, EDIF_TOK_PORTREF, EDIF_TOK_PORTLIST, EDIF_TOK_BECOMES, EDIF_TOK_TRANSITION}; static short f_Circle[] = {EDIF_TOK_PT, EDIF_TOK_PROPERTY}; static short f_Color[] = {EDIF_TOK_E}; static short f_CommentGraphics[] = {EDIF_TOK_ANNOTATE, EDIF_TOK_FIGURE, EDIF_TOK_INSTANCE, -EDIF_TOK_BOUNDINGBOX, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Compound[] = {EDIF_TOK_NAME}; static short f_ConnectLocation[] = {EDIF_TOK_FIGURE}; static short f_Contents[] = {EDIF_TOK_INSTANCE, EDIF_TOK_OFFPAGECONNECTOR, EDIF_TOK_FIGURE, EDIF_TOK_SECTION, EDIF_TOK_NET, EDIF_TOK_NETBUNDLE, EDIF_TOK_PAGE, EDIF_TOK_COMMENTGRAPHICS, EDIF_TOK_PORTIMPLEMENTATION, EDIF_TOK_TIMING, EDIF_TOK_SIMULATE, EDIF_TOK_WHEN, EDIF_TOK_FOLLOW, EDIF_TOK_LOGICPORT, -EDIF_TOK_BOUNDINGBOX, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Criticality[] = {EDIF_TOK_INTEGERDISPLAY}; static short f_CurrentMap[] = {EDIF_TOK_MNM, EDIF_TOK_E}; static short f_Curve[] = {EDIF_TOK_ARC, EDIF_TOK_PT}; static short f_Cycle[] = {EDIF_TOK_DURATION}; static short f_DataOrigin[] = {EDIF_TOK_VERSION}; static short f_DcFanInLoad[] = {EDIF_TOK_E, EDIF_TOK_NUMBERDISPLAY}; static short f_DcFanOutLoad[] = {EDIF_TOK_E, EDIF_TOK_NUMBERDISPLAY}; static short f_DcMaxFanIn[] = {EDIF_TOK_E, EDIF_TOK_NUMBERDISPLAY}; static short f_DcMaxFanOut[] = {EDIF_TOK_E, EDIF_TOK_NUMBERDISPLAY}; static short f_Delay[] = {EDIF_TOK_MNM, EDIF_TOK_E}; static short f_Delta[] = {EDIF_TOK_PT}; static short f_Design[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_CELLREF, EDIF_TOK_STATUS, EDIF_TOK_COMMENT, EDIF_TOK_PROPERTY, EDIF_TOK_USERDATA}; static short f_Designator[] = {EDIF_TOK_STRINGDISPLAY}; static short f_Difference[] = {EDIF_TOK_FIGUREGROUPREF, EDIF_TOK_INTERSECTION, EDIF_TOK_UNION, EDIF_TOK_DIFFERENCE, EDIF_TOK_INVERSE, EDIF_TOK_OVERSIZE}; static short f_Display[] = {EDIF_TOK_NAME, EDIF_TOK_FIGUREGROUPOVERRIDE, EDIF_TOK_JUSTIFY, EDIF_TOK_ORIENTATION, EDIF_TOK_ORIGIN}; static short f_Dominates[] = {EDIF_TOK_NAME}; static short f_Dot[] = {EDIF_TOK_PT, EDIF_TOK_PROPERTY}; static short f_Duration[] = {EDIF_TOK_E}; static short f_EnclosureDistance[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Entry[] = {EDIF_TOK_MATCH, EDIF_TOK_CHANGE, EDIF_TOK_STEADY, EDIF_TOK_LOGICREF, EDIF_TOK_PORTREF, EDIF_TOK_NOCHANGE, EDIF_TOK_TABLE, EDIF_TOK_DELAY, EDIF_TOK_LOADDELAY}; static short f_Exactly[] = {EDIF_TOK_E}; static short f_External[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_EDIFLEVEL, EDIF_TOK_TECHNOLOGY, -EDIF_TOK_STATUS, EDIF_TOK_CELL, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Fabricate[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME}; static short f_Figure[] = {EDIF_TOK_NAME, EDIF_TOK_FIGUREGROUPOVERRIDE, EDIF_TOK_CIRCLE, EDIF_TOK_DOT, EDIF_TOK_OPENSHAPE, EDIF_TOK_PATH, EDIF_TOK_POLYGON, EDIF_TOK_RECTANGLE, EDIF_TOK_SHAPE, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_FigureArea[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_FigureGroup[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, -EDIF_TOK_CORNERTYPE, -EDIF_TOK_ENDTYPE, -EDIF_TOK_PATHWIDTH, -EDIF_TOK_BORDERWIDTH, -EDIF_TOK_COLOR, -EDIF_TOK_FILLPATTERN, -EDIF_TOK_BORDERPATTERN, -EDIF_TOK_TEXTHEIGHT, -EDIF_TOK_VISIBLE, EDIF_TOK_INCLUDEFIGUREGROUP, EDIF_TOK_COMMENT, EDIF_TOK_PROPERTY, EDIF_TOK_USERDATA}; static short f_FigureGroupObject[] = {EDIF_TOK_NAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_INTERSECTION, EDIF_TOK_UNION, EDIF_TOK_DIFFERENCE, EDIF_TOK_INVERSE, EDIF_TOK_OVERSIZE}; static short f_FigureGroupOverride[] = {EDIF_TOK_NAME, -EDIF_TOK_CORNERTYPE, -EDIF_TOK_ENDTYPE, -EDIF_TOK_PATHWIDTH, -EDIF_TOK_BORDERWIDTH, -EDIF_TOK_COLOR, -EDIF_TOK_FILLPATTERN, -EDIF_TOK_TEXTHEIGHT, -EDIF_TOK_BORDERPATTERN, EDIF_TOK_VISIBLE, EDIF_TOK_COMMENT, EDIF_TOK_PROPERTY, EDIF_TOK_USERDATA}; static short f_FigureGroupRef[] = {EDIF_TOK_NAME, EDIF_TOK_LIBRARYREF}; static short f_FigurePerimeter[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_FigureWidth[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_FillPattern[] = {EDIF_TOK_BOOLEAN}; static short f_Follow[] = {EDIF_TOK_NAME, EDIF_TOK_PORTREF, EDIF_TOK_TABLE, EDIF_TOK_DELAY, EDIF_TOK_LOADDELAY}; static short f_ForbiddenEvent[] = {EDIF_TOK_TIMEINTERVAL, EDIF_TOK_EVENT}; static short f_GlobalPortRef[] = {EDIF_TOK_NAME}; static short f_GreaterThan[] = {EDIF_TOK_E}; static short f_GridMap[] = {EDIF_TOK_E}; static short f_IncludeFigureGroup[] = {EDIF_TOK_FIGUREGROUPREF, EDIF_TOK_INTERSECTION, EDIF_TOK_UNION, EDIF_TOK_DIFFERENCE, EDIF_TOK_INVERSE, EDIF_TOK_OVERSIZE}; static short f_Instance[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_ARRAY, EDIF_TOK_VIEWREF, EDIF_TOK_VIEWLIST, -EDIF_TOK_TRANSFORM, EDIF_TOK_PARAMETERASSIGN, EDIF_TOK_PORTINSTANCE, EDIF_TOK_TIMING, -EDIF_TOK_DESIGNATOR, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_InstanceBackAnnotate[] = {EDIF_TOK_INSTANCEREF, -EDIF_TOK_DESIGNATOR, EDIF_TOK_TIMING, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT}; static short f_InstanceGroup[] = {EDIF_TOK_INSTANCEREF}; static short f_InstanceMap[] = {EDIF_TOK_INSTANCEREF, EDIF_TOK_INSTANCEGROUP, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_InstanceRef[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_INSTANCEREF, EDIF_TOK_VIEWREF}; static short f_Integer[] = {EDIF_TOK_INTEGERDISPLAY, EDIF_TOK_INTEGER}; static short f_IntegerDisplay[] = {EDIF_TOK_DISPLAY}; static short f_Interface[] = {EDIF_TOK_PORT, EDIF_TOK_PORTBUNDLE, -EDIF_TOK_SYMBOL, -EDIF_TOK_PROTECTIONFRAME, -EDIF_TOK_ARRAYRELATEDINFO, EDIF_TOK_PARAMETER, EDIF_TOK_JOINED, EDIF_TOK_MUSTJOIN, EDIF_TOK_WEAKJOINED, EDIF_TOK_PERMUTABLE, EDIF_TOK_TIMING, EDIF_TOK_SIMULATE, -EDIF_TOK_DESIGNATOR, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_InterFigureGroupSpacing[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Intersection[] = {EDIF_TOK_FIGUREGROUPREF, EDIF_TOK_INTERSECTION, EDIF_TOK_UNION, EDIF_TOK_DIFFERENCE, EDIF_TOK_INVERSE, EDIF_TOK_OVERSIZE}; static short f_IntraFigureGroupSpacing[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Inverse[] = {EDIF_TOK_FIGUREGROUPREF, EDIF_TOK_INTERSECTION, EDIF_TOK_UNION, EDIF_TOK_DIFFERENCE, EDIF_TOK_INVERSE, EDIF_TOK_OVERSIZE}; static short f_Joined[] = {EDIF_TOK_PORTREF, EDIF_TOK_PORTLIST, EDIF_TOK_GLOBALPORTREF}; static short f_KeywordDisplay[] = {EDIF_TOK_DISPLAY}; static short f_KeywordMap[] = {EDIF_TOK_KEYWORDLEVEL, EDIF_TOK_COMMENT}; static short f_LessThan[] = {EDIF_TOK_E}; static short f_Library[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_EDIFLEVEL, EDIF_TOK_TECHNOLOGY, -EDIF_TOK_STATUS, EDIF_TOK_CELL, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_LibraryRef[] = {EDIF_TOK_NAME}; static short f_ListOfNets[] = {EDIF_TOK_NET}; static short f_ListOfPorts[] = {EDIF_TOK_PORT, EDIF_TOK_PORTBUNDLE}; static short f_LoadDelay[] = {EDIF_TOK_MNM, EDIF_TOK_E, EDIF_TOK_MINOMAXDISPLAY}; static short f_LogicAssign[] = {EDIF_TOK_NAME, EDIF_TOK_PORTREF, EDIF_TOK_LOGICREF, EDIF_TOK_TABLE, EDIF_TOK_DELAY, EDIF_TOK_LOADDELAY}; static short f_LogicInput[] = {EDIF_TOK_PORTLIST, EDIF_TOK_PORTREF, EDIF_TOK_NAME, EDIF_TOK_LOGICWAVEFORM}; static short f_LogicList[] = {EDIF_TOK_NAME, EDIF_TOK_LOGICONEOF, EDIF_TOK_IGNORE}; static short f_LogicMapInput[] = {EDIF_TOK_LOGICREF}; static short f_LogicMapOutput[] = {EDIF_TOK_LOGICREF}; static short f_LogicOneOf[] = {EDIF_TOK_NAME, EDIF_TOK_LOGICLIST}; static short f_LogicOutput[] = {EDIF_TOK_PORTLIST, EDIF_TOK_PORTREF, EDIF_TOK_NAME, EDIF_TOK_LOGICWAVEFORM}; static short f_LogicPort[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_LogicRef[] = {EDIF_TOK_NAME, EDIF_TOK_LIBRARYREF}; static short f_LogicValue[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, -EDIF_TOK_VOLTAGEMAP, -EDIF_TOK_CURRENTMAP, -EDIF_TOK_BOOLEANMAP, -EDIF_TOK_COMPOUND, -EDIF_TOK_WEAK ,-EDIF_TOK_STRONG, -EDIF_TOK_DOMINATES, -EDIF_TOK_LOGICMAPOUTPUT, -EDIF_TOK_LOGICMAPINPUT, -EDIF_TOK_ISOLATED, EDIF_TOK_RESOLVES, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_LogicWaveform[] = {EDIF_TOK_NAME, EDIF_TOK_LOGICLIST, EDIF_TOK_LOGICONEOF, EDIF_TOK_IGNORE}; static short f_Maintain[] = {EDIF_TOK_NAME, EDIF_TOK_PORTREF, EDIF_TOK_DELAY, EDIF_TOK_LOADDELAY}; static short f_Match[] = {EDIF_TOK_NAME, EDIF_TOK_PORTREF, EDIF_TOK_PORTLIST, EDIF_TOK_LOGICLIST, EDIF_TOK_LOGICONEOF}; static short f_Member[] = {EDIF_TOK_NAME}; static short f_MiNoMax[] = {EDIF_TOK_MNM, EDIF_TOK_E, EDIF_TOK_MINOMAXDISPLAY, EDIF_TOK_MINOMAX}; static short f_MiNoMaxDisplay[] = {EDIF_TOK_MNM, EDIF_TOK_E, EDIF_TOK_DISPLAY}; static short f_Mnm[] = {EDIF_TOK_E, EDIF_TOK_UNDEFINED, EDIF_TOK_UNCONSTRAINED}; static short f_MultipleValueSet[] = {EDIF_TOK_RANGEVECTOR}; static short f_MustJoin[] = {EDIF_TOK_PORTREF, EDIF_TOK_PORTLIST, EDIF_TOK_WEAKJOINED, EDIF_TOK_JOINED}; static short f_Name[] = {EDIF_TOK_DISPLAY}; static short f_Net[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, -EDIF_TOK_CRITICALITY, EDIF_TOK_NETDELAY, EDIF_TOK_FIGURE, EDIF_TOK_NET, EDIF_TOK_INSTANCE, EDIF_TOK_COMMENTGRAPHICS, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA, EDIF_TOK_JOINED, EDIF_TOK_ARRAY}; static short f_NetBackAnnotate[] = {EDIF_TOK_NETREF, EDIF_TOK_NETDELAY, -EDIF_TOK_CRITICALITY, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT}; static short f_NetBundle[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_ARRAY, EDIF_TOK_LISTOFNETS, EDIF_TOK_FIGURE, EDIF_TOK_COMMENTGRAPHICS, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_NetDelay[] = {EDIF_TOK_DERIVATION, EDIF_TOK_DELAY, EDIF_TOK_TRANSITION, EDIF_TOK_BECOMES}; static short f_NetGroup[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_NETREF}; static short f_NetMap[] = {EDIF_TOK_NETREF, EDIF_TOK_NETGROUP, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_NetRef[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_NETREF, EDIF_TOK_INSTANCEREF, EDIF_TOK_VIEWREF}; static short f_NonPermutable[] = {EDIF_TOK_PORTREF, EDIF_TOK_PERMUTABLE}; static short f_NotAllowed[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_NotchSpacing[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Number[] = {EDIF_TOK_E, EDIF_TOK_NUMBERDISPLAY, EDIF_TOK_NUMBER}; static short f_NumberDefinition[] = {EDIF_TOK_SCALE, -EDIF_TOK_GRIDMAP, EDIF_TOK_COMMENT}; static short f_NumberDisplay[] = {EDIF_TOK_E, EDIF_TOK_DISPLAY}; static short f_OffPageConnector[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, -EDIF_TOK_UNUSED, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_OffsetEvent[] = {EDIF_TOK_EVENT, EDIF_TOK_E}; static short f_OpenShape[] = {EDIF_TOK_CURVE, EDIF_TOK_PROPERTY}; static short f_Origin[] = {EDIF_TOK_PT}; static short f_OverhangDistance[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_OverlapDistance[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Oversize[] = {EDIF_TOK_FIGUREGROUPREF, EDIF_TOK_INTERSECTION, EDIF_TOK_UNION, EDIF_TOK_DIFFERENCE, EDIF_TOK_INVERSE, EDIF_TOK_OVERSIZE, EDIF_TOK_CORNERTYPE}; static short f_Page[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_ARRAY, EDIF_TOK_INSTANCE, EDIF_TOK_NET, EDIF_TOK_NETBUNDLE, EDIF_TOK_COMMENTGRAPHICS, EDIF_TOK_PORTIMPLEMENTATION, -EDIF_TOK_PAGESIZE, -EDIF_TOK_BOUNDINGBOX, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_PageSize[] = {EDIF_TOK_RECTANGLE}; static short f_Parameter[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_ARRAY, EDIF_TOK_BOOLEAN, EDIF_TOK_INTEGER, EDIF_TOK_MINOMAX, EDIF_TOK_NUMBER, EDIF_TOK_POINT, EDIF_TOK_STRING}; static short f_ParameterAssign[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_BOOLEAN, EDIF_TOK_INTEGER, EDIF_TOK_MINOMAX, EDIF_TOK_NUMBER, EDIF_TOK_POINT, EDIF_TOK_STRING}; static short f_ParameterDisplay[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_DISPLAY}; static short f_Path[] = {EDIF_TOK_POINTLIST, EDIF_TOK_PROPERTY}; static short f_PathDelay[] = {EDIF_TOK_DELAY, EDIF_TOK_EVENT}; static short f_Permutable[] = {EDIF_TOK_PORTREF, EDIF_TOK_PERMUTABLE, EDIF_TOK_NONPERMUTABLE}; static short f_PhysicalDesignRule[] = {EDIF_TOK_FIGUREWIDTH, EDIF_TOK_FIGUREAREA, EDIF_TOK_RECTANGLESIZE, EDIF_TOK_FIGUREPERIMETER, EDIF_TOK_OVERLAPDISTANCE, EDIF_TOK_OVERHANGDISTANCE, EDIF_TOK_ENCLOSUREDISTANCE, EDIF_TOK_INTERFIGUREGROUPSPACING, EDIF_TOK_NOTCHSPACING, EDIF_TOK_INTRAFIGUREGROUPSPACING, EDIF_TOK_NOTALLOWED, EDIF_TOK_FIGUREGROUP, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Plug[] = {EDIF_TOK_SOCKETSET}; static short f_Point[] = {EDIF_TOK_PT, EDIF_TOK_POINTDISPLAY, EDIF_TOK_POINT}; static short f_PointDisplay[] = {EDIF_TOK_PT, EDIF_TOK_DISPLAY}; static short f_PointList[] = {EDIF_TOK_PT}; static short f_Polygon[] = {EDIF_TOK_POINTLIST, EDIF_TOK_PROPERTY}; static short f_Port[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_ARRAY, -EDIF_TOK_DIRECTION, -EDIF_TOK_UNUSED, EDIF_TOK_PORTDELAY, -EDIF_TOK_DESIGNATOR, -EDIF_TOK_DCFANINLOAD, -EDIF_TOK_DCFANOUTLOAD, -EDIF_TOK_DCMAXFANIN, -EDIF_TOK_DCMAXFANOUT, -EDIF_TOK_ACLOAD, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_PortBackAnnotate[] = {EDIF_TOK_PORTREF, -EDIF_TOK_DESIGNATOR, EDIF_TOK_PORTDELAY, -EDIF_TOK_DCFANINLOAD, -EDIF_TOK_DCFANOUTLOAD, -EDIF_TOK_DCMAXFANIN, -EDIF_TOK_DCMAXFANOUT, -EDIF_TOK_ACLOAD, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT}; static short f_PortBundle[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_ARRAY, EDIF_TOK_LISTOFPORTS, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_PortDelay[] = {EDIF_TOK_DERIVATION, EDIF_TOK_DELAY, EDIF_TOK_LOADDELAY, EDIF_TOK_TRANSITION, EDIF_TOK_BECOMES}; static short f_PortGroup[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_PORTREF}; static short f_PortImplementation[] = {EDIF_TOK_PORTREF, EDIF_TOK_NAME, EDIF_TOK_MEMBER, -EDIF_TOK_CONNECTLOCATION, EDIF_TOK_FIGURE, EDIF_TOK_INSTANCE, EDIF_TOK_COMMENTGRAPHICS, EDIF_TOK_PROPERTYDISPLAY, EDIF_TOK_KEYWORDDISPLAY, EDIF_TOK_PROPERTY, EDIF_TOK_USERDATA, EDIF_TOK_COMMENT}; static short f_PortInstance[] = {EDIF_TOK_PORTREF, EDIF_TOK_NAME, EDIF_TOK_MEMBER, -EDIF_TOK_UNUSED, EDIF_TOK_PORTDELAY, -EDIF_TOK_DESIGNATOR, -EDIF_TOK_DCFANINLOAD, -EDIF_TOK_DCFANOUTLOAD, -EDIF_TOK_DCMAXFANIN, -EDIF_TOK_DCMAXFANOUT, -EDIF_TOK_ACLOAD, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_PortList[] = {EDIF_TOK_PORTREF, EDIF_TOK_NAME, EDIF_TOK_MEMBER}; static short f_PortListAlias[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_ARRAY, EDIF_TOK_PORTLIST}; static short f_PortMap[] = {EDIF_TOK_PORTREF, EDIF_TOK_PORTGROUP, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_PortRef[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_PORTREF, EDIF_TOK_INSTANCEREF, EDIF_TOK_VIEWREF}; static short f_Program[] = {EDIF_TOK_VERSION}; static short f_Property[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_BOOLEAN, EDIF_TOK_INTEGER, EDIF_TOK_MINOMAX, EDIF_TOK_NUMBER, EDIF_TOK_POINT, EDIF_TOK_STRING, -EDIF_TOK_OWNER, -EDIF_TOK_UNIT, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT}; static short f_PropertyDisplay[] = {EDIF_TOK_NAME, EDIF_TOK_DISPLAY}; static short f_ProtectionFrame[] = {EDIF_TOK_PORTIMPLEMENTATION, EDIF_TOK_FIGURE, EDIF_TOK_INSTANCE, EDIF_TOK_COMMENTGRAPHICS, -EDIF_TOK_BOUNDINGBOX, EDIF_TOK_PROPERTYDISPLAY, EDIF_TOK_KEYWORDDISPLAY, EDIF_TOK_PARAMETERDISPLAY, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_RangeVector[] = {EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN, EDIF_TOK_SINGLEVALUESET}; static short f_Rectangle[] = {EDIF_TOK_PT, EDIF_TOK_PROPERTY}; static short f_RectangleSize[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_FIGUREGROUPOBJECT, EDIF_TOK_RANGEVECTOR, EDIF_TOK_MULTIPLEVALUESET,EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Rename[] = {EDIF_TOK_NAME, EDIF_TOK_STRINGDISPLAY}; static short f_Resolves[] = {EDIF_TOK_NAME}; static short f_Scale[] = {EDIF_TOK_E, EDIF_TOK_UNIT}; static short f_Section[] = {EDIF_TOK_SECTION, EDIF_TOK_INSTANCE}; static short f_Shape[] = {EDIF_TOK_CURVE, EDIF_TOK_PROPERTY}; static short f_Simulate[] = {EDIF_TOK_NAME, EDIF_TOK_PORTLISTALIAS, EDIF_TOK_WAVEVALUE, EDIF_TOK_APPLY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_SimulationInfo[] = {EDIF_TOK_LOGICVALUE, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_SingleValueSet[] = {EDIF_TOK_LESSTHAN, EDIF_TOK_GREATERTHAN, EDIF_TOK_ATMOST, EDIF_TOK_ATLEAST, EDIF_TOK_EXACTLY, EDIF_TOK_BETWEEN}; static short f_Site[] = {EDIF_TOK_VIEWREF, EDIF_TOK_TRANSFORM}; static short f_Socket[] = {EDIF_TOK_SYMMETRY}; static short f_SocketSet[] = {EDIF_TOK_SYMMETRY, EDIF_TOK_SITE}; static short f_Status[] = {EDIF_TOK_WRITTEN, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Steady[] = {EDIF_TOK_NAME, EDIF_TOK_MEMBER, EDIF_TOK_PORTREF, EDIF_TOK_PORTLIST, EDIF_TOK_DURATION, EDIF_TOK_TRANSITION, EDIF_TOK_BECOMES}; static short f_String[] = {EDIF_TOK_STRINGDISPLAY, EDIF_TOK_STRING}; static short f_StringDisplay[] = {EDIF_TOK_DISPLAY}; static short f_Strong[] = {EDIF_TOK_NAME}; static short f_Symbol[] = {EDIF_TOK_PORTIMPLEMENTATION, EDIF_TOK_FIGURE, EDIF_TOK_INSTANCE, EDIF_TOK_COMMENTGRAPHICS, EDIF_TOK_ANNOTATE, -EDIF_TOK_PAGESIZE, -EDIF_TOK_BOUNDINGBOX, EDIF_TOK_PROPERTYDISPLAY, EDIF_TOK_KEYWORDDISPLAY, EDIF_TOK_PARAMETERDISPLAY, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Symmetry[] = {EDIF_TOK_TRANSFORM}; static short f_Table[] = {EDIF_TOK_ENTRY, EDIF_TOK_TABLEDEFAULT}; static short f_TableDefault[] = {EDIF_TOK_LOGICREF, EDIF_TOK_PORTREF, EDIF_TOK_NOCHANGE, EDIF_TOK_TABLE, EDIF_TOK_DELAY, EDIF_TOK_LOADDELAY}; static short f_Technology[] = {EDIF_TOK_NUMBERDEFINITION, EDIF_TOK_FIGUREGROUP, EDIF_TOK_FABRICATE, -EDIF_TOK_SIMULATIONINFO, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA, -EDIF_TOK_PHYSICALDESIGNRULE}; static short f_TimeInterval[] = {EDIF_TOK_EVENT, EDIF_TOK_OFFSETEVENT, EDIF_TOK_DURATION}; static short f_Timing[] = {EDIF_TOK_DERIVATION, EDIF_TOK_PATHDELAY, EDIF_TOK_FORBIDDENEVENT, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Transform[] = {EDIF_TOK_SCALEX, EDIF_TOK_SCALEY, EDIF_TOK_DELTA, EDIF_TOK_ORIENTATION, EDIF_TOK_ORIGIN}; static short f_Transition[] = {EDIF_TOK_NAME, EDIF_TOK_LOGICLIST, EDIF_TOK_LOGICONEOF}; static short f_Trigger[] = {EDIF_TOK_CHANGE, EDIF_TOK_STEADY, EDIF_TOK_INITIAL}; static short f_Union[] = {EDIF_TOK_FIGUREGROUPREF, EDIF_TOK_INTERSECTION, EDIF_TOK_UNION, EDIF_TOK_DIFFERENCE, EDIF_TOK_INVERSE, EDIF_TOK_OVERSIZE}; static short f_View[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_VIEWTYPE, EDIF_TOK_INTERFACE, -EDIF_TOK_STATUS, -EDIF_TOK_CONTENTS, EDIF_TOK_COMMENT, EDIF_TOK_PROPERTY, EDIF_TOK_USERDATA}; static short f_ViewList[] = {EDIF_TOK_VIEWREF, EDIF_TOK_VIEWLIST}; static short f_ViewMap[] = {EDIF_TOK_PORTMAP, EDIF_TOK_PORTBACKANNOTATE, EDIF_TOK_INSTANCEMAP, EDIF_TOK_INSTANCEBACKANNOTATE, EDIF_TOK_NETMAP, EDIF_TOK_NETBACKANNOTATE, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_ViewRef[] = {EDIF_TOK_NAME, EDIF_TOK_CELLREF}; static short f_Visible[] = {EDIF_TOK_FALSE, EDIF_TOK_TRUE}; static short f_VoltageMap[] = {EDIF_TOK_MNM, EDIF_TOK_E}; static short f_WaveValue[] = {EDIF_TOK_NAME, EDIF_TOK_RENAME, EDIF_TOK_E, EDIF_TOK_LOGICWAVEFORM}; static short f_Weak[] = {EDIF_TOK_NAME}; static short f_WeakJoined[] = {EDIF_TOK_PORTREF, EDIF_TOK_PORTLIST, EDIF_TOK_JOINED}; static short f_When[] = {EDIF_TOK_TRIGGER, EDIF_TOK_AFTER, EDIF_TOK_FOLLOW, EDIF_TOK_MAINTAIN, EDIF_TOK_LOGICASSIGN, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; static short f_Written[] = {EDIF_TOK_TIMESTAMP, EDIF_TOK_AUTHOR, EDIF_TOK_PROGRAM, EDIF_TOK_DATAORIGIN, EDIF_TOK_PROPERTY, EDIF_TOK_COMMENT, EDIF_TOK_USERDATA}; /* * Context binding table: * * This binds context follower arrays to their originating context. */ typedef struct Binder { short *Follower; /* pointer to follower array */ short Origin; /* '%token' value of origin */ short FollowerSize; /* size of follower array */ } Binder; #define BE(f,o) {f,o,sizeof(f)/sizeof(short)} static Binder BinderDef[] = { BE(f_NULL, 0), BE(f_Edif, EDIF_TOK_EDIF), BE(f_AcLoad, EDIF_TOK_ACLOAD), BE(f_After, EDIF_TOK_AFTER), BE(f_Annotate, EDIF_TOK_ANNOTATE), BE(f_Apply, EDIF_TOK_APPLY), BE(f_Arc, EDIF_TOK_ARC), BE(f_Array, EDIF_TOK_ARRAY), BE(f_ArrayMacro, EDIF_TOK_ARRAYMACRO), BE(f_ArrayRelatedInfo, EDIF_TOK_ARRAYRELATEDINFO), BE(f_ArraySite, EDIF_TOK_ARRAYSITE), BE(f_AtLeast, EDIF_TOK_ATLEAST), BE(f_AtMost, EDIF_TOK_ATMOST), BE(f_Becomes, EDIF_TOK_BECOMES), BE(f_Boolean, EDIF_TOK_BOOLEAN), BE(f_BooleanDisplay, EDIF_TOK_BOOLEANDISPLAY), BE(f_BooleanMap, EDIF_TOK_BOOLEANMAP), BE(f_BorderPattern, EDIF_TOK_BORDERPATTERN), BE(f_BoundingBox, EDIF_TOK_BOUNDINGBOX), BE(f_Cell, EDIF_TOK_CELL), BE(f_CellRef, EDIF_TOK_CELLREF), BE(f_Change, EDIF_TOK_CHANGE), BE(f_Circle, EDIF_TOK_CIRCLE), BE(f_Color, EDIF_TOK_COLOR), BE(f_CommentGraphics, EDIF_TOK_COMMENTGRAPHICS), BE(f_Compound, EDIF_TOK_COMPOUND), BE(f_ConnectLocation, EDIF_TOK_CONNECTLOCATION), BE(f_Contents, EDIF_TOK_CONTENTS), BE(f_Criticality, EDIF_TOK_CRITICALITY), BE(f_CurrentMap, EDIF_TOK_CURRENTMAP), BE(f_Curve, EDIF_TOK_CURVE), BE(f_Cycle, EDIF_TOK_CYCLE), BE(f_DataOrigin, EDIF_TOK_DATAORIGIN), BE(f_DcFanInLoad, EDIF_TOK_DCFANINLOAD), BE(f_DcFanOutLoad, EDIF_TOK_DCFANOUTLOAD), BE(f_DcMaxFanIn, EDIF_TOK_DCMAXFANIN), BE(f_DcMaxFanOut, EDIF_TOK_DCMAXFANOUT), BE(f_Delay, EDIF_TOK_DELAY), BE(f_Delta, EDIF_TOK_DELTA), BE(f_Design, EDIF_TOK_DESIGN), BE(f_Designator, EDIF_TOK_DESIGNATOR), BE(f_Difference, EDIF_TOK_DIFFERENCE), BE(f_Display, EDIF_TOK_DISPLAY), BE(f_Dominates, EDIF_TOK_DOMINATES), BE(f_Dot, EDIF_TOK_DOT), BE(f_Duration, EDIF_TOK_DURATION), BE(f_EnclosureDistance, EDIF_TOK_ENCLOSUREDISTANCE), BE(f_Entry, EDIF_TOK_ENTRY), BE(f_Exactly, EDIF_TOK_EXACTLY), BE(f_External, EDIF_TOK_EXTERNAL), BE(f_Fabricate, EDIF_TOK_FABRICATE), BE(f_Figure, EDIF_TOK_FIGURE), BE(f_FigureArea, EDIF_TOK_FIGUREAREA), BE(f_FigureGroup, EDIF_TOK_FIGUREGROUP), BE(f_FigureGroupObject, EDIF_TOK_FIGUREGROUPOBJECT), BE(f_FigureGroupOverride, EDIF_TOK_FIGUREGROUPOVERRIDE), BE(f_FigureGroupRef, EDIF_TOK_FIGUREGROUPREF), BE(f_FigurePerimeter, EDIF_TOK_FIGUREPERIMETER), BE(f_FigureWidth, EDIF_TOK_FIGUREWIDTH), BE(f_FillPattern, EDIF_TOK_FILLPATTERN), BE(f_Follow, EDIF_TOK_FOLLOW), BE(f_ForbiddenEvent, EDIF_TOK_FORBIDDENEVENT), BE(f_GlobalPortRef, EDIF_TOK_GLOBALPORTREF), BE(f_GreaterThan, EDIF_TOK_GREATERTHAN), BE(f_GridMap, EDIF_TOK_GRIDMAP), BE(f_IncludeFigureGroup, EDIF_TOK_INCLUDEFIGUREGROUP), BE(f_Instance, EDIF_TOK_INSTANCE), BE(f_InstanceBackAnnotate, EDIF_TOK_INSTANCEBACKANNOTATE), BE(f_InstanceGroup, EDIF_TOK_INSTANCEGROUP), BE(f_InstanceMap, EDIF_TOK_INSTANCEMAP), BE(f_InstanceRef, EDIF_TOK_INSTANCEREF), BE(f_Integer, EDIF_TOK_INTEGER), BE(f_IntegerDisplay, EDIF_TOK_INTEGERDISPLAY), BE(f_InterFigureGroupSpacing, EDIF_TOK_INTERFIGUREGROUPSPACING), BE(f_Interface, EDIF_TOK_INTERFACE), BE(f_Intersection, EDIF_TOK_INTERSECTION), BE(f_IntraFigureGroupSpacing, EDIF_TOK_INTRAFIGUREGROUPSPACING), BE(f_Inverse, EDIF_TOK_INVERSE), BE(f_Joined, EDIF_TOK_JOINED), BE(f_KeywordDisplay, EDIF_TOK_KEYWORDDISPLAY), BE(f_KeywordMap, EDIF_TOK_KEYWORDMAP), BE(f_LessThan, EDIF_TOK_LESSTHAN), BE(f_Library, EDIF_TOK_LIBRARY), BE(f_LibraryRef, EDIF_TOK_LIBRARYREF), BE(f_ListOfNets, EDIF_TOK_LISTOFNETS), BE(f_ListOfPorts, EDIF_TOK_LISTOFPORTS), BE(f_LoadDelay, EDIF_TOK_LOADDELAY), BE(f_LogicAssign, EDIF_TOK_LOGICASSIGN), BE(f_LogicInput, EDIF_TOK_LOGICINPUT), BE(f_LogicList, EDIF_TOK_LOGICLIST), BE(f_LogicMapInput, EDIF_TOK_LOGICMAPINPUT), BE(f_LogicMapOutput, EDIF_TOK_LOGICMAPOUTPUT), BE(f_LogicOneOf, EDIF_TOK_LOGICONEOF), BE(f_LogicOutput, EDIF_TOK_LOGICOUTPUT), BE(f_LogicPort, EDIF_TOK_LOGICPORT), BE(f_LogicRef, EDIF_TOK_LOGICREF), BE(f_LogicValue, EDIF_TOK_LOGICVALUE), BE(f_LogicWaveform, EDIF_TOK_LOGICWAVEFORM), BE(f_Maintain, EDIF_TOK_MAINTAIN), BE(f_Match, EDIF_TOK_MATCH), BE(f_Member, EDIF_TOK_MEMBER), BE(f_MiNoMax, EDIF_TOK_MINOMAX), BE(f_MiNoMaxDisplay, EDIF_TOK_MINOMAXDISPLAY), BE(f_Mnm, EDIF_TOK_MNM), BE(f_MultipleValueSet, EDIF_TOK_MULTIPLEVALUESET), BE(f_MustJoin, EDIF_TOK_MUSTJOIN), BE(f_Name, EDIF_TOK_NAME), BE(f_Net, EDIF_TOK_NET), BE(f_NetBackAnnotate, EDIF_TOK_NETBACKANNOTATE), BE(f_NetBundle, EDIF_TOK_NETBUNDLE), BE(f_NetDelay, EDIF_TOK_NETDELAY), BE(f_NetGroup, EDIF_TOK_NETGROUP), BE(f_NetMap, EDIF_TOK_NETMAP), BE(f_NetRef, EDIF_TOK_NETREF), BE(f_NonPermutable, EDIF_TOK_NONPERMUTABLE), BE(f_NotAllowed, EDIF_TOK_NOTALLOWED), BE(f_NotchSpacing, EDIF_TOK_NOTCHSPACING), BE(f_Number, EDIF_TOK_NUMBER), BE(f_NumberDefinition, EDIF_TOK_NUMBERDEFINITION), BE(f_NumberDisplay, EDIF_TOK_NUMBERDISPLAY), BE(f_OffPageConnector, EDIF_TOK_OFFPAGECONNECTOR), BE(f_OffsetEvent, EDIF_TOK_OFFSETEVENT), BE(f_OpenShape, EDIF_TOK_OPENSHAPE), BE(f_Origin, EDIF_TOK_ORIGIN), BE(f_OverhangDistance, EDIF_TOK_OVERHANGDISTANCE), BE(f_OverlapDistance, EDIF_TOK_OVERLAPDISTANCE), BE(f_Oversize, EDIF_TOK_OVERSIZE), BE(f_Page, EDIF_TOK_PAGE), BE(f_PageSize, EDIF_TOK_PAGESIZE), BE(f_Parameter, EDIF_TOK_PARAMETER), BE(f_ParameterAssign, EDIF_TOK_PARAMETERASSIGN), BE(f_ParameterDisplay, EDIF_TOK_PARAMETERDISPLAY), BE(f_Path, EDIF_TOK_PATH), BE(f_PathDelay, EDIF_TOK_PATHDELAY), BE(f_Permutable, EDIF_TOK_PERMUTABLE), BE(f_PhysicalDesignRule, EDIF_TOK_PHYSICALDESIGNRULE), BE(f_Plug, EDIF_TOK_PLUG), BE(f_Point, EDIF_TOK_POINT), BE(f_PointDisplay, EDIF_TOK_POINTDISPLAY), BE(f_PointList, EDIF_TOK_POINTLIST), BE(f_Polygon, EDIF_TOK_POLYGON), BE(f_Port, EDIF_TOK_PORT), BE(f_PortBackAnnotate, EDIF_TOK_PORTBACKANNOTATE), BE(f_PortBundle, EDIF_TOK_PORTBUNDLE), BE(f_PortDelay, EDIF_TOK_PORTDELAY), BE(f_PortGroup, EDIF_TOK_PORTGROUP), BE(f_PortImplementation, EDIF_TOK_PORTIMPLEMENTATION), BE(f_PortInstance, EDIF_TOK_PORTINSTANCE), BE(f_PortList, EDIF_TOK_PORTLIST), BE(f_PortListAlias, EDIF_TOK_PORTLISTALIAS), BE(f_PortMap, EDIF_TOK_PORTMAP), BE(f_PortRef, EDIF_TOK_PORTREF), BE(f_Program, EDIF_TOK_PROGRAM), BE(f_Property, EDIF_TOK_PROPERTY), BE(f_PropertyDisplay, EDIF_TOK_PROPERTYDISPLAY), BE(f_ProtectionFrame, EDIF_TOK_PROTECTIONFRAME), BE(f_RangeVector, EDIF_TOK_RANGEVECTOR), BE(f_Rectangle, EDIF_TOK_RECTANGLE), BE(f_RectangleSize, EDIF_TOK_RECTANGLESIZE), BE(f_Rename, EDIF_TOK_RENAME), BE(f_Resolves, EDIF_TOK_RESOLVES), BE(f_Scale, EDIF_TOK_SCALE), BE(f_Section, EDIF_TOK_SECTION), BE(f_Shape, EDIF_TOK_SHAPE), BE(f_Simulate, EDIF_TOK_SIMULATE), BE(f_SimulationInfo, EDIF_TOK_SIMULATIONINFO), BE(f_SingleValueSet, EDIF_TOK_SINGLEVALUESET), BE(f_Site, EDIF_TOK_SITE), BE(f_Socket, EDIF_TOK_SOCKET), BE(f_SocketSet, EDIF_TOK_SOCKETSET), BE(f_Status, EDIF_TOK_STATUS), BE(f_Steady, EDIF_TOK_STEADY), BE(f_String, EDIF_TOK_STRING), BE(f_StringDisplay, EDIF_TOK_STRINGDISPLAY), BE(f_Strong, EDIF_TOK_STRONG), BE(f_Symbol, EDIF_TOK_SYMBOL), BE(f_Symmetry, EDIF_TOK_SYMMETRY), BE(f_Table, EDIF_TOK_TABLE), BE(f_TableDefault, EDIF_TOK_TABLEDEFAULT), BE(f_Technology, EDIF_TOK_TECHNOLOGY), BE(f_TimeInterval, EDIF_TOK_TIMEINTERVAL), BE(f_Timing, EDIF_TOK_TIMING), BE(f_Transform, EDIF_TOK_TRANSFORM), BE(f_Transition, EDIF_TOK_TRANSITION), BE(f_Trigger, EDIF_TOK_TRIGGER), BE(f_Union, EDIF_TOK_UNION), BE(f_View, EDIF_TOK_VIEW), BE(f_ViewList, EDIF_TOK_VIEWLIST), BE(f_ViewMap, EDIF_TOK_VIEWMAP), BE(f_ViewRef, EDIF_TOK_VIEWREF), BE(f_Visible, EDIF_TOK_VISIBLE), BE(f_VoltageMap, EDIF_TOK_VOLTAGEMAP), BE(f_WaveValue, EDIF_TOK_WAVEVALUE), BE(f_Weak, EDIF_TOK_WEAK), BE(f_WeakJoined, EDIF_TOK_WEAKJOINED), BE(f_When, EDIF_TOK_WHEN), BE(f_Written, EDIF_TOK_WRITTEN) }; static int BinderDefSize = sizeof(BinderDef) / sizeof(Binder); /* * Keyword table: * * This hash table holds all strings which may have to be matched * to. WARNING: it is assumed that there is no overlap of the 'token' * and 'context' strings. */ typedef struct Keyword { struct Keyword *Next; /* pointer to next entry */ char *String; /* pointer to associated string */ } Keyword; #define KEYWORD_HASH 127 /* hash table size */ static Keyword *KeywordTable[KEYWORD_HASH]; /* * Enter keyword: * * The passed string is entered into the keyword hash table. */ static void EnterKeyword(char * str) { /* * Locals. */ register Keyword *key; register unsigned int hsh; register char *cp; /* * Create the hash code, and add an entry to the table. */ for (hsh = 0, cp = str; *cp; hsh += hsh + *cp++); hsh %= KEYWORD_HASH; key = (Keyword *) Malloc(sizeof(Keyword)); key->Next = KeywordTable[hsh]; (KeywordTable[hsh] = key)->String = str; } /* * Find keyword: * * The passed string is located within the keyword table. If an * entry exists, then the value of the keyword string is returned. This * is real useful for doing string comparisons by pointer value later. * If there is no match, a NULL is returned. */ static char *FindKeyword(char * str) { /* * Locals. */ register Keyword *wlk,*owk; register unsigned int hsh; register char *cp; char lower[IDENT_LENGTH + 1]; /* * Create a lower case copy of the string. */ for (cp = lower; *str;) if (isupper( (int) *str)) *cp++ = tolower( (int) *str++); else *cp++ = *str++; *cp = '\0'; /* * Search the hash table for a match. */ for (hsh = 0, cp = lower; *cp; hsh += hsh + *cp++); hsh %= KEYWORD_HASH; for (owk = NULL, wlk = KeywordTable[hsh]; wlk; wlk = (owk = wlk)->Next) if (!strcmp(wlk->String,lower)){ /* * Readjust the LRU. */ if (owk){ owk->Next = wlk->Next; wlk->Next = KeywordTable[hsh]; KeywordTable[hsh] = wlk; } return (wlk->String); } return (NULL); } /* * Token hash table. */ #define TOKEN_HASH 51 static Token *TokenHash[TOKEN_HASH]; /* * Find token: * * A pointer to the token of the passed code is returned. If * no such beastie is present a NULL is returned instead. */ static Token *FindToken(register int cod) { /* * Locals. */ register Token *wlk,*owk; register unsigned int hsh; /* * Search the hash table for a matching token. */ hsh = cod % TOKEN_HASH; for (owk = NULL, wlk = TokenHash[hsh]; wlk; wlk = (owk = wlk)->Next) if (cod == wlk->Code){ if (owk){ owk->Next = wlk->Next; wlk->Next = TokenHash[hsh]; TokenHash[hsh] = wlk; } break; } return (wlk); } /* * Context hash table. */ #define CONTEXT_HASH 127 static Context *ContextHash[CONTEXT_HASH]; /* * Find context: * * A pointer to the context of the passed code is returned. If * no such beastie is present a NULL is returned instead. */ static Context *FindContext(register int cod) { /* * Locals. */ register Context *wlk,*owk; register unsigned int hsh; /* * Search the hash table for a matching context. */ hsh = cod % CONTEXT_HASH; for (owk = NULL, wlk = ContextHash[hsh]; wlk; wlk = (owk = wlk)->Next) if (cod == wlk->Code){ if (owk){ owk->Next = wlk->Next; wlk->Next = ContextHash[hsh]; ContextHash[hsh] = wlk; } break; } return (wlk); } /* * Parser state variables. */ static FILE *Input = NULL; /* input stream */ static FILE *Error = NULL; /* error stream */ static char *InFile; /* file name on the input stream */ static long LineNumber; /* current input line number */ static ContextCar *CSP = NULL; /* top of context stack */ static char yytext[IDENT_LENGTH + 1]; /* token buffer */ static char CharBuf[IDENT_LENGTH + 1]; /* garbage buffer */ /* * Token stacking variables. */ #ifdef DEBUG #define TS_DEPTH 8 #define TS_MASK (TS_DEPTH - 1) static unsigned int TSP = 0; /* token stack pointer */ static char *TokenStack[TS_DEPTH]; /* token name strings */ static short TokenType[TS_DEPTH]; /* token types */ /* * Stack: * * Add a token to the debug stack. The passed string and type are * what is to be pushed. */ static int Stack(char * str, int typ) { /* * Free any previous string, then push. */ if (TokenStack[TSP & TS_MASK]) Free(TokenStack[TSP & TS_MASK]); TokenStack[TSP & TS_MASK] = strcpy((char *)Malloc(strlen(str) + 1),str); TokenType[TSP & TS_MASK] = typ; TSP += 1; return 0; } /* * Dump stack: * * This displays the last set of accumulated tokens. */ static int DumpStack() { /* * Locals. */ register int i; register Context *cxt; register Token *tok; register char *nam; /* * Run through the list displaying the oldest first. */ fprintf(Error,"\n\n"); for (i = 0; i < TS_DEPTH; i += 1) if (TokenStack[(TSP + i) & TS_MASK]){ /* * Get the type name string. */ if ((cxt = FindContext(TokenType[(TSP + i) & TS_MASK]))) nam = cxt->Name; else if ((tok = FindToken(TokenType[(TSP + i) & TS_MASK]))) nam = tok->Name; else switch (TokenType[(TSP + i) & TS_MASK]){ case EDIF_TOK_IDENT: nam = "IDENT"; break; case EDIF_TOK_INT: nam = "INT"; break; case EDIF_TOK_KEYWORD: nam = "KEYWORD"; break; case EDIF_TOK_STR: nam = "STR"; break; default: nam = "?"; break; } /* * Now print the token state. */ fprintf(Error,"%2d %-16.16s '%s'\n",TS_DEPTH - i,nam, TokenStack[(TSP + i) & TS_MASK]); } fprintf(Error,"\n"); return 0; } #else #define Stack(s,t) #endif /* DEBUG */ /* * yyerror: * * Standard error reporter, it prints out the passed string * preceeded by the current filename and line number. */ static void yyerror(const char *ers) { #ifdef DEBUG DumpStack(); #endif /* DEBUG */ fprintf(Error,"%s, line %ld: %s\n",InFile,LineNumber,ers); } /* * String bucket definitions. */ #define BUCKET_SIZE 64 typedef struct Bucket { struct Bucket *Next; /* pointer to next bucket */ int Index; /* pointer to next free slot */ char Data[BUCKET_SIZE]; /* string data */ } Bucket; static Bucket *CurrentBucket = NULL; /* string bucket list */ static int StringSize = 0; /* current string length */ /* * Push string: * * This adds the passed charater to the current string bucket. */ static void PushString(char chr) { /* * Locals. */ register Bucket *bck; /* * Make sure there is room for the push. */ if ((bck = CurrentBucket)->Index >= BUCKET_SIZE){ bck = (Bucket *) Malloc(sizeof(Bucket)); bck->Next = CurrentBucket; (CurrentBucket = bck)->Index = 0; } /* * Push the character. */ bck->Data[bck->Index++] = chr; StringSize += 1; } /* * Form string: * * This converts the current string bucket into a real live string, * whose pointer is returned. */ static char *FormString() { /* * Locals. */ register Bucket *bck; register char *cp; /* * Allocate space for the string, set the pointer at the end. */ cp = (char *) Malloc(StringSize + 1); cp += StringSize; *cp-- = '\0'; /* * Yank characters out of the bucket. */ for (bck = CurrentBucket; bck->Index || bck->Next;){ if (!bck->Index){ CurrentBucket = bck->Next; Free(bck); bck = CurrentBucket; } *cp-- = bck->Data[--bck->Index]; } /* reset buffer size to zero */ StringSize =0; return (cp + 1); } /* * Parse EDIF: * * This builds the context tree and then calls the real parser. * It is passed two file streams, the first is where the input comes * from; the second is where error messages get printed. */ void ParseEDIF(char* filename,FILE* err) { /* * Locals. */ register int i; static int ContextDefined = 1; /* * Set up the file state to something useful. */ InFile = filename; Input = fopen(filename,"r"); Error = err; LineNumber = 1; /* * Define both the enabled token and context strings. */ if (ContextDefined){ for (i = TokenDefSize; i--; EnterKeyword(TokenDef[i].Name)){ register unsigned int hsh; hsh = TokenDef[i].Code % TOKEN_HASH; TokenDef[i].Next = TokenHash[hsh]; TokenHash[hsh] = &TokenDef[i]; } for (i = ContextDefSize; i--; EnterKeyword(ContextDef[i].Name)){ register unsigned int hsh; hsh = ContextDef[i].Code % CONTEXT_HASH; ContextDef[i].Next = ContextHash[hsh]; ContextHash[hsh] = &ContextDef[i]; } /* * Build the context tree. */ for (i = BinderDefSize; i--;){ register Context *cxt; register int j; /* * Define the current context to have carriers bound to it. */ cxt = FindContext(BinderDef[i].Origin); for (j = BinderDef[i].FollowerSize; j--;){ register ContextCar *cc; /* * Add carriers to the current context. */ cc = (ContextCar *) Malloc(sizeof(ContextCar)); cc->Next = cxt->Context; (cxt->Context = cc)->Context = FindContext(ABS(BinderDef[i].Follower[j])); cc->u.Single = BinderDef[i].Follower[j] < 0; } } /* * Build the token tree. */ for (i = TieDefSize; i--;){ register Context *cxt; register int j; /* * Define the current context to have carriers bound to it. */ cxt = FindContext(TieDef[i].Origin); for (j = TieDef[i].EnableSize; j--;){ register TokenCar *tc; /* * Add carriers to the current context. */ tc = (TokenCar *) Malloc(sizeof(TokenCar)); tc->Next = cxt->Token; (cxt->Token = tc)->Token = FindToken(TieDef[i].Enable[j]); } } /* * Put a bogus context on the stack which has 'EDIF' as its * follower. */ CSP = (ContextCar *) Malloc(sizeof(ContextCar)); CSP->Next = NULL; CSP->Context = FindContext(0); CSP->u.Used = NULL; ContextDefined = 0; } /* * Create an initial, empty string bucket. */ CurrentBucket = (Bucket *) Malloc(sizeof(Bucket)); CurrentBucket->Next = 0; CurrentBucket->Index = 0; /* * Fill the token stack with NULLs if debugging is enabled. */ #ifdef DEBUG for (i = TS_DEPTH; i--; TokenStack[i] = NULL) if (TokenStack[i]) Free(TokenStack[i]); TSP = 0; #endif /* DEBUG */ /* * Go parse things! */ edifparse(); } /* * Match token: * * The passed string is looked up in the current context's token * list to see if it is enabled. If so the token value is returned, * if not then zero. */ static int MatchToken(register char * str) { /* * Locals. */ register TokenCar *wlk,*owk; /* * Convert the string to the proper form, then search the token * carrier list for a match. */ str = FindKeyword(str); for (owk = NULL, wlk = CSP->Context->Token; wlk; wlk = (owk = wlk)->Next) if (str == wlk->Token->Name){ if (owk){ owk->Next = wlk->Next; wlk->Next = CSP->Context->Token; CSP->Context->Token = wlk; } return (wlk->Token->Code); } return (0); } /* * Match context: * * If the passed keyword string is within the current context, the * new context is pushed and token value is returned. A zero otherwise. */ static int MatchContext(register char * str) { /* * Locals. */ register ContextCar *wlk,*owk; /* * See if the context is present. */ str = FindKeyword(str); for (owk = NULL, wlk = CSP->Context->Context; wlk; wlk = (owk = wlk)->Next) if (str == wlk->Context->Name){ if (owk){ owk->Next = wlk->Next; wlk->Next = CSP->Context->Context; CSP->Context->Context = wlk; } /* * If a single context, make sure it isn't already used. */ if (wlk->u.Single){ register UsedCar *usc; for (usc = CSP->u.Used; usc; usc = usc->Next) if (usc->Code == wlk->Context->Code) break; if (usc){ sprintf(CharBuf,"'%s' is used more than once within '%s'", str,CSP->Context->Name); yyerror(CharBuf); } else { usc = (UsedCar *) Malloc(sizeof(UsedCar)); usc->Next = CSP->u.Used; (CSP->u.Used = usc)->Code = wlk->Context->Code; } } /* * Push the new context. */ owk = (ContextCar *) Malloc(sizeof(ContextCar)); owk->Next = CSP; (CSP = owk)->Context = wlk->Context; owk->u.Used = NULL; return (wlk->Context->Code); } return (0); } /* * PopC: * * This pops the current context. */ static void PopC() { /* * Locals. */ register UsedCar *usc; register ContextCar *csp; /* * Release single markers and pop context. */ while ( (usc = CSP->u.Used) ){ CSP->u.Used = usc->Next; Free(usc); } csp = CSP->Next; Free(CSP); CSP = csp; } /* * Lexical analyzer states. */ #define L_START 0 #define L_INT 1 #define L_IDENT 2 #define L_KEYWORD 3 #define L_STRING 4 #define L_KEYWORD2 5 #define L_ASCIICHAR 6 #define L_ASCIICHAR2 7 /* * yylex: * * This is the lexical analyzer called by the YACC/BISON parser. * It returns a pretty restricted set of token types and does the * context movement when acceptable keywords are found. The token * value returned is a NULL terminated string to allocated storage * (ie - it should get released some time) with some restrictions. * The token value for integers is strips a leading '+' if present. * String token values have the leading and trailing '"'-s stripped. * '%' conversion characters in string values are passed converted. * The '(' and ')' characters do not have a token value. */ static int yylex() { /* * Locals. */ register int c,s,l; /* * Keep on sucking up characters until we find something which * explicitly forces us out of this function. */ for (s = L_START, l = 0; 1;){ yytext[l++] = c = Getc(Input); switch (s){ /* * Starting state, look for something resembling a token. */ case L_START: if (isdigit(c) || c == '-') s = L_INT; else if (isalpha(c) || c == '&') s = L_IDENT; else if (isspace(c)){ if (c == '\n') LineNumber += 1; l = 0; } else if (c == '('){ l = 0; s = L_KEYWORD; } else if (c == '"') s = L_STRING; else if (c == '+'){ l = 0; /* strip '+' */ s = L_INT; } else if (c == EOF) return ('\0'); else { yytext[1] = '\0'; Stack(yytext,c); return (c); } break; /* * Suck up the integer digits. */ case L_INT: if (isdigit(c)) break; Ungetc(c); yytext[--l] = '\0'; yylval.s = strcpy((char *)Malloc(l + 1),yytext); Stack(yytext,EDIF_TOK_INT); return (EDIF_TOK_INT); /* * Grab an identifier, see if the current context enables * it with a specific token value. */ case L_IDENT: if (isalpha(c) || isdigit(c) || c == '_') break; Ungetc(c); yytext[--l] = '\0'; if (CSP->Context->Token && (c = MatchToken(yytext))){ Stack(yytext,c); return (c); } yylval.s = strcpy((char *)Malloc(l + 1),yytext); Stack(yytext, EDIF_TOK_IDENT); return (EDIF_TOK_IDENT); /* * Scan until you find the start of an identifier, discard * any whitespace found. On no identifier, return a '('. */ case L_KEYWORD: if (isalpha(c) || c == '&'){ s = L_KEYWORD2; break; } else if (isspace(c)){ l = 0; break; } Ungetc(c); Stack("(",'('); return ('('); /* * Suck up the keyword identifier, if it matches the set of * allowable contexts then return its token value and push * the context, otherwise just return the identifier string. */ case L_KEYWORD2: if (isalpha(c) || isdigit(c) || c == '_') break; Ungetc(c); yytext[--l] = '\0'; if ( (c = MatchContext(yytext)) ){ Stack(yytext,c); return (c); } yylval.s = strcpy((char *)Malloc(l + 1),yytext); Stack(yytext, EDIF_TOK_KEYWORD); return (EDIF_TOK_KEYWORD); /* * Suck up string characters but once resolved they should * be deposited in the string bucket because they can be * arbitrarily long. */ case L_STRING: if (c == '\n') LineNumber += 1; else if (c == '\r') ; else if (c == '"' || c == EOF){ yylval.s = FormString(); Stack(yylval.s, EDIF_TOK_STR); return (EDIF_TOK_STR); } else if (c == '%') s = L_ASCIICHAR; else PushString(c); l = 0; break; /* * Skip white space and look for integers to be pushed * as characters. */ case L_ASCIICHAR: if (isdigit(c)){ s = L_ASCIICHAR2; break; } else if (c == '%' || c == EOF) s = L_STRING; else if (c == '\n') LineNumber += 1; l = 0; break; /* * Convert the accumulated integer into a char and push. */ case L_ASCIICHAR2: if (isdigit(c)) break; Ungetc(c); yytext[--l] = '\0'; PushString(atoi(yytext)); s = L_ASCIICHAR; l = 0; break; } } } pcb-4.2.2/src/edif.h0000664000076400007640000004723113113114461011067 00000000000000 /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton interface for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { EDIF_TOK_IDENT = 258, EDIF_TOK_INT = 259, EDIF_TOK_KEYWORD = 260, EDIF_TOK_STR = 261, EDIF_TOK_ANGLE = 262, EDIF_TOK_BEHAVIOR = 263, EDIF_TOK_CALCULATED = 264, EDIF_TOK_CAPACITANCE = 265, EDIF_TOK_CENTERCENTER = 266, EDIF_TOK_CENTERLEFT = 267, EDIF_TOK_CENTERRIGHT = 268, EDIF_TOK_CHARGE = 269, EDIF_TOK_CONDUCTANCE = 270, EDIF_TOK_CURRENT = 271, EDIF_TOK_DISTANCE = 272, EDIF_TOK_DOCUMENT = 273, EDIF_TOK_ENERGY = 274, EDIF_TOK_EXTEND = 275, EDIF_TOK_FLUX = 276, EDIF_TOK_FREQUENCY = 277, EDIF_TOK_GENERIC = 278, EDIF_TOK_GRAPHIC = 279, EDIF_TOK_INDUCTANCE = 280, EDIF_TOK_INOUT = 281, EDIF_TOK_INPUT = 282, EDIF_TOK_LOGICMODEL = 283, EDIF_TOK_LOWERCENTER = 284, EDIF_TOK_LOWERLEFT = 285, EDIF_TOK_LOWERRIGHT = 286, EDIF_TOK_MASKLAYOUT = 287, EDIF_TOK_MASS = 288, EDIF_TOK_MEASURED = 289, EDIF_TOK_MX = 290, EDIF_TOK_MXR90 = 291, EDIF_TOK_MY = 292, EDIF_TOK_MYR90 = 293, EDIF_TOK_NETLIST = 294, EDIF_TOK_OUTPUT = 295, EDIF_TOK_PCBLAYOUT = 296, EDIF_TOK_POWER = 297, EDIF_TOK_R0 = 298, EDIF_TOK_R180 = 299, EDIF_TOK_R270 = 300, EDIF_TOK_R90 = 301, EDIF_TOK_REQUIRED = 302, EDIF_TOK_RESISTANCE = 303, EDIF_TOK_RIPPER = 304, EDIF_TOK_ROUND = 305, EDIF_TOK_SCHEMATIC = 306, EDIF_TOK_STRANGER = 307, EDIF_TOK_SYMBOLIC = 308, EDIF_TOK_TEMPERATURE = 309, EDIF_TOK_TIE = 310, EDIF_TOK_TIME = 311, EDIF_TOK_TRUNCATE = 312, EDIF_TOK_UPPERCENTER = 313, EDIF_TOK_UPPERLEFT = 314, EDIF_TOK_UPPERRIGHT = 315, EDIF_TOK_VOLTAGE = 316, EDIF_TOK_ACLOAD = 317, EDIF_TOK_AFTER = 318, EDIF_TOK_ANNOTATE = 319, EDIF_TOK_APPLY = 320, EDIF_TOK_ARC = 321, EDIF_TOK_ARRAY = 322, EDIF_TOK_ARRAYMACRO = 323, EDIF_TOK_ARRAYRELATEDINFO = 324, EDIF_TOK_ARRAYSITE = 325, EDIF_TOK_ATLEAST = 326, EDIF_TOK_ATMOST = 327, EDIF_TOK_AUTHOR = 328, EDIF_TOK_BASEARRAY = 329, EDIF_TOK_BECOMES = 330, EDIF_TOK_BETWEEN = 331, EDIF_TOK_BOOLEAN = 332, EDIF_TOK_BOOLEANDISPLAY = 333, EDIF_TOK_BOOLEANMAP = 334, EDIF_TOK_BORDERPATTERN = 335, EDIF_TOK_BORDERWIDTH = 336, EDIF_TOK_BOUNDINGBOX = 337, EDIF_TOK_CELL = 338, EDIF_TOK_CELLREF = 339, EDIF_TOK_CELLTYPE = 340, EDIF_TOK_CHANGE = 341, EDIF_TOK_CIRCLE = 342, EDIF_TOK_COLOR = 343, EDIF_TOK_COMMENT = 344, EDIF_TOK_COMMENTGRAPHICS = 345, EDIF_TOK_COMPOUND = 346, EDIF_TOK_CONNECTLOCATION = 347, EDIF_TOK_CONTENTS = 348, EDIF_TOK_CORNERTYPE = 349, EDIF_TOK_CRITICALITY = 350, EDIF_TOK_CURRENTMAP = 351, EDIF_TOK_CURVE = 352, EDIF_TOK_CYCLE = 353, EDIF_TOK_DATAORIGIN = 354, EDIF_TOK_DCFANINLOAD = 355, EDIF_TOK_DCFANOUTLOAD = 356, EDIF_TOK_DCMAXFANIN = 357, EDIF_TOK_DCMAXFANOUT = 358, EDIF_TOK_DELAY = 359, EDIF_TOK_DELTA = 360, EDIF_TOK_DERIVATION = 361, EDIF_TOK_DESIGN = 362, EDIF_TOK_DESIGNATOR = 363, EDIF_TOK_DIFFERENCE = 364, EDIF_TOK_DIRECTION = 365, EDIF_TOK_DISPLAY = 366, EDIF_TOK_DOMINATES = 367, EDIF_TOK_DOT = 368, EDIF_TOK_DURATION = 369, EDIF_TOK_E = 370, EDIF_TOK_EDIF = 371, EDIF_TOK_EDIFLEVEL = 372, EDIF_TOK_EDIFVERSION = 373, EDIF_TOK_ENCLOSUREDISTANCE = 374, EDIF_TOK_ENDTYPE = 375, EDIF_TOK_ENTRY = 376, EDIF_TOK_EVENT = 377, EDIF_TOK_EXACTLY = 378, EDIF_TOK_EXTERNAL = 379, EDIF_TOK_FABRICATE = 380, EDIF_TOK_FALSE = 381, EDIF_TOK_FIGURE = 382, EDIF_TOK_FIGUREAREA = 383, EDIF_TOK_FIGUREGROUP = 384, EDIF_TOK_FIGUREGROUPOBJECT = 385, EDIF_TOK_FIGUREGROUPOVERRIDE = 386, EDIF_TOK_FIGUREGROUPREF = 387, EDIF_TOK_FIGUREPERIMETER = 388, EDIF_TOK_FIGUREWIDTH = 389, EDIF_TOK_FILLPATTERN = 390, EDIF_TOK_FOLLOW = 391, EDIF_TOK_FORBIDDENEVENT = 392, EDIF_TOK_GLOBALPORTREF = 393, EDIF_TOK_GREATERTHAN = 394, EDIF_TOK_GRIDMAP = 395, EDIF_TOK_IGNORE = 396, EDIF_TOK_INCLUDEFIGUREGROUP = 397, EDIF_TOK_INITIAL = 398, EDIF_TOK_INSTANCE = 399, EDIF_TOK_INSTANCEBACKANNOTATE = 400, EDIF_TOK_INSTANCEGROUP = 401, EDIF_TOK_INSTANCEMAP = 402, EDIF_TOK_INSTANCEREF = 403, EDIF_TOK_INTEGER = 404, EDIF_TOK_INTEGERDISPLAY = 405, EDIF_TOK_INTERFACE = 406, EDIF_TOK_INTERFIGUREGROUPSPACING = 407, EDIF_TOK_INTERSECTION = 408, EDIF_TOK_INTRAFIGUREGROUPSPACING = 409, EDIF_TOK_INVERSE = 410, EDIF_TOK_ISOLATED = 411, EDIF_TOK_JOINED = 412, EDIF_TOK_JUSTIFY = 413, EDIF_TOK_KEYWORDDISPLAY = 414, EDIF_TOK_KEYWORDLEVEL = 415, EDIF_TOK_KEYWORDMAP = 416, EDIF_TOK_LESSTHAN = 417, EDIF_TOK_LIBRARY = 418, EDIF_TOK_LIBRARYREF = 419, EDIF_TOK_LISTOFNETS = 420, EDIF_TOK_LISTOFPORTS = 421, EDIF_TOK_LOADDELAY = 422, EDIF_TOK_LOGICASSIGN = 423, EDIF_TOK_LOGICINPUT = 424, EDIF_TOK_LOGICLIST = 425, EDIF_TOK_LOGICMAPINPUT = 426, EDIF_TOK_LOGICMAPOUTPUT = 427, EDIF_TOK_LOGICONEOF = 428, EDIF_TOK_LOGICOUTPUT = 429, EDIF_TOK_LOGICPORT = 430, EDIF_TOK_LOGICREF = 431, EDIF_TOK_LOGICVALUE = 432, EDIF_TOK_LOGICWAVEFORM = 433, EDIF_TOK_MAINTAIN = 434, EDIF_TOK_MATCH = 435, EDIF_TOK_MEMBER = 436, EDIF_TOK_MINOMAX = 437, EDIF_TOK_MINOMAXDISPLAY = 438, EDIF_TOK_MNM = 439, EDIF_TOK_MULTIPLEVALUESET = 440, EDIF_TOK_MUSTJOIN = 441, EDIF_TOK_NAME = 442, EDIF_TOK_NET = 443, EDIF_TOK_NETBACKANNOTATE = 444, EDIF_TOK_NETBUNDLE = 445, EDIF_TOK_NETDELAY = 446, EDIF_TOK_NETGROUP = 447, EDIF_TOK_NETMAP = 448, EDIF_TOK_NETREF = 449, EDIF_TOK_NOCHANGE = 450, EDIF_TOK_NONPERMUTABLE = 451, EDIF_TOK_NOTALLOWED = 452, EDIF_TOK_NOTCHSPACING = 453, EDIF_TOK_NUMBER = 454, EDIF_TOK_NUMBERDEFINITION = 455, EDIF_TOK_NUMBERDISPLAY = 456, EDIF_TOK_OFFPAGECONNECTOR = 457, EDIF_TOK_OFFSETEVENT = 458, EDIF_TOK_OPENSHAPE = 459, EDIF_TOK_ORIENTATION = 460, EDIF_TOK_ORIGIN = 461, EDIF_TOK_OVERHANGDISTANCE = 462, EDIF_TOK_OVERLAPDISTANCE = 463, EDIF_TOK_OVERSIZE = 464, EDIF_TOK_OWNER = 465, EDIF_TOK_PAGE = 466, EDIF_TOK_PAGESIZE = 467, EDIF_TOK_PARAMETER = 468, EDIF_TOK_PARAMETERASSIGN = 469, EDIF_TOK_PARAMETERDISPLAY = 470, EDIF_TOK_PATH = 471, EDIF_TOK_PATHDELAY = 472, EDIF_TOK_PATHWIDTH = 473, EDIF_TOK_PERMUTABLE = 474, EDIF_TOK_PHYSICALDESIGNRULE = 475, EDIF_TOK_PLUG = 476, EDIF_TOK_POINT = 477, EDIF_TOK_POINTDISPLAY = 478, EDIF_TOK_POINTLIST = 479, EDIF_TOK_POLYGON = 480, EDIF_TOK_PORT = 481, EDIF_TOK_PORTBACKANNOTATE = 482, EDIF_TOK_PORTBUNDLE = 483, EDIF_TOK_PORTDELAY = 484, EDIF_TOK_PORTGROUP = 485, EDIF_TOK_PORTIMPLEMENTATION = 486, EDIF_TOK_PORTINSTANCE = 487, EDIF_TOK_PORTLIST = 488, EDIF_TOK_PORTLISTALIAS = 489, EDIF_TOK_PORTMAP = 490, EDIF_TOK_PORTREF = 491, EDIF_TOK_PROGRAM = 492, EDIF_TOK_PROPERTY = 493, EDIF_TOK_PROPERTYDISPLAY = 494, EDIF_TOK_PROTECTIONFRAME = 495, EDIF_TOK_PT = 496, EDIF_TOK_RANGEVECTOR = 497, EDIF_TOK_RECTANGLE = 498, EDIF_TOK_RECTANGLESIZE = 499, EDIF_TOK_RENAME = 500, EDIF_TOK_RESOLVES = 501, EDIF_TOK_SCALE = 502, EDIF_TOK_SCALEX = 503, EDIF_TOK_SCALEY = 504, EDIF_TOK_SECTION = 505, EDIF_TOK_SHAPE = 506, EDIF_TOK_SIMULATE = 507, EDIF_TOK_SIMULATIONINFO = 508, EDIF_TOK_SINGLEVALUESET = 509, EDIF_TOK_SITE = 510, EDIF_TOK_SOCKET = 511, EDIF_TOK_SOCKETSET = 512, EDIF_TOK_STATUS = 513, EDIF_TOK_STEADY = 514, EDIF_TOK_STRING = 515, EDIF_TOK_STRINGDISPLAY = 516, EDIF_TOK_STRONG = 517, EDIF_TOK_SYMBOL = 518, EDIF_TOK_SYMMETRY = 519, EDIF_TOK_TABLE = 520, EDIF_TOK_TABLEDEFAULT = 521, EDIF_TOK_TECHNOLOGY = 522, EDIF_TOK_TEXTHEIGHT = 523, EDIF_TOK_TIMEINTERVAL = 524, EDIF_TOK_TIMESTAMP = 525, EDIF_TOK_TIMING = 526, EDIF_TOK_TRANSFORM = 527, EDIF_TOK_TRANSITION = 528, EDIF_TOK_TRIGGER = 529, EDIF_TOK_TRUE = 530, EDIF_TOK_UNCONSTRAINED = 531, EDIF_TOK_UNDEFINED = 532, EDIF_TOK_UNION = 533, EDIF_TOK_UNIT = 534, EDIF_TOK_UNUSED = 535, EDIF_TOK_USERDATA = 536, EDIF_TOK_VERSION = 537, EDIF_TOK_VIEW = 538, EDIF_TOK_VIEWLIST = 539, EDIF_TOK_VIEWMAP = 540, EDIF_TOK_VIEWREF = 541, EDIF_TOK_VIEWTYPE = 542, EDIF_TOK_VISIBLE = 543, EDIF_TOK_VOLTAGEMAP = 544, EDIF_TOK_WAVEVALUE = 545, EDIF_TOK_WEAK = 546, EDIF_TOK_WEAKJOINED = 547, EDIF_TOK_WHEN = 548, EDIF_TOK_WRITTEN = 549 }; #endif /* Tokens. */ #define EDIF_TOK_IDENT 258 #define EDIF_TOK_INT 259 #define EDIF_TOK_KEYWORD 260 #define EDIF_TOK_STR 261 #define EDIF_TOK_ANGLE 262 #define EDIF_TOK_BEHAVIOR 263 #define EDIF_TOK_CALCULATED 264 #define EDIF_TOK_CAPACITANCE 265 #define EDIF_TOK_CENTERCENTER 266 #define EDIF_TOK_CENTERLEFT 267 #define EDIF_TOK_CENTERRIGHT 268 #define EDIF_TOK_CHARGE 269 #define EDIF_TOK_CONDUCTANCE 270 #define EDIF_TOK_CURRENT 271 #define EDIF_TOK_DISTANCE 272 #define EDIF_TOK_DOCUMENT 273 #define EDIF_TOK_ENERGY 274 #define EDIF_TOK_EXTEND 275 #define EDIF_TOK_FLUX 276 #define EDIF_TOK_FREQUENCY 277 #define EDIF_TOK_GENERIC 278 #define EDIF_TOK_GRAPHIC 279 #define EDIF_TOK_INDUCTANCE 280 #define EDIF_TOK_INOUT 281 #define EDIF_TOK_INPUT 282 #define EDIF_TOK_LOGICMODEL 283 #define EDIF_TOK_LOWERCENTER 284 #define EDIF_TOK_LOWERLEFT 285 #define EDIF_TOK_LOWERRIGHT 286 #define EDIF_TOK_MASKLAYOUT 287 #define EDIF_TOK_MASS 288 #define EDIF_TOK_MEASURED 289 #define EDIF_TOK_MX 290 #define EDIF_TOK_MXR90 291 #define EDIF_TOK_MY 292 #define EDIF_TOK_MYR90 293 #define EDIF_TOK_NETLIST 294 #define EDIF_TOK_OUTPUT 295 #define EDIF_TOK_PCBLAYOUT 296 #define EDIF_TOK_POWER 297 #define EDIF_TOK_R0 298 #define EDIF_TOK_R180 299 #define EDIF_TOK_R270 300 #define EDIF_TOK_R90 301 #define EDIF_TOK_REQUIRED 302 #define EDIF_TOK_RESISTANCE 303 #define EDIF_TOK_RIPPER 304 #define EDIF_TOK_ROUND 305 #define EDIF_TOK_SCHEMATIC 306 #define EDIF_TOK_STRANGER 307 #define EDIF_TOK_SYMBOLIC 308 #define EDIF_TOK_TEMPERATURE 309 #define EDIF_TOK_TIE 310 #define EDIF_TOK_TIME 311 #define EDIF_TOK_TRUNCATE 312 #define EDIF_TOK_UPPERCENTER 313 #define EDIF_TOK_UPPERLEFT 314 #define EDIF_TOK_UPPERRIGHT 315 #define EDIF_TOK_VOLTAGE 316 #define EDIF_TOK_ACLOAD 317 #define EDIF_TOK_AFTER 318 #define EDIF_TOK_ANNOTATE 319 #define EDIF_TOK_APPLY 320 #define EDIF_TOK_ARC 321 #define EDIF_TOK_ARRAY 322 #define EDIF_TOK_ARRAYMACRO 323 #define EDIF_TOK_ARRAYRELATEDINFO 324 #define EDIF_TOK_ARRAYSITE 325 #define EDIF_TOK_ATLEAST 326 #define EDIF_TOK_ATMOST 327 #define EDIF_TOK_AUTHOR 328 #define EDIF_TOK_BASEARRAY 329 #define EDIF_TOK_BECOMES 330 #define EDIF_TOK_BETWEEN 331 #define EDIF_TOK_BOOLEAN 332 #define EDIF_TOK_BOOLEANDISPLAY 333 #define EDIF_TOK_BOOLEANMAP 334 #define EDIF_TOK_BORDERPATTERN 335 #define EDIF_TOK_BORDERWIDTH 336 #define EDIF_TOK_BOUNDINGBOX 337 #define EDIF_TOK_CELL 338 #define EDIF_TOK_CELLREF 339 #define EDIF_TOK_CELLTYPE 340 #define EDIF_TOK_CHANGE 341 #define EDIF_TOK_CIRCLE 342 #define EDIF_TOK_COLOR 343 #define EDIF_TOK_COMMENT 344 #define EDIF_TOK_COMMENTGRAPHICS 345 #define EDIF_TOK_COMPOUND 346 #define EDIF_TOK_CONNECTLOCATION 347 #define EDIF_TOK_CONTENTS 348 #define EDIF_TOK_CORNERTYPE 349 #define EDIF_TOK_CRITICALITY 350 #define EDIF_TOK_CURRENTMAP 351 #define EDIF_TOK_CURVE 352 #define EDIF_TOK_CYCLE 353 #define EDIF_TOK_DATAORIGIN 354 #define EDIF_TOK_DCFANINLOAD 355 #define EDIF_TOK_DCFANOUTLOAD 356 #define EDIF_TOK_DCMAXFANIN 357 #define EDIF_TOK_DCMAXFANOUT 358 #define EDIF_TOK_DELAY 359 #define EDIF_TOK_DELTA 360 #define EDIF_TOK_DERIVATION 361 #define EDIF_TOK_DESIGN 362 #define EDIF_TOK_DESIGNATOR 363 #define EDIF_TOK_DIFFERENCE 364 #define EDIF_TOK_DIRECTION 365 #define EDIF_TOK_DISPLAY 366 #define EDIF_TOK_DOMINATES 367 #define EDIF_TOK_DOT 368 #define EDIF_TOK_DURATION 369 #define EDIF_TOK_E 370 #define EDIF_TOK_EDIF 371 #define EDIF_TOK_EDIFLEVEL 372 #define EDIF_TOK_EDIFVERSION 373 #define EDIF_TOK_ENCLOSUREDISTANCE 374 #define EDIF_TOK_ENDTYPE 375 #define EDIF_TOK_ENTRY 376 #define EDIF_TOK_EVENT 377 #define EDIF_TOK_EXACTLY 378 #define EDIF_TOK_EXTERNAL 379 #define EDIF_TOK_FABRICATE 380 #define EDIF_TOK_FALSE 381 #define EDIF_TOK_FIGURE 382 #define EDIF_TOK_FIGUREAREA 383 #define EDIF_TOK_FIGUREGROUP 384 #define EDIF_TOK_FIGUREGROUPOBJECT 385 #define EDIF_TOK_FIGUREGROUPOVERRIDE 386 #define EDIF_TOK_FIGUREGROUPREF 387 #define EDIF_TOK_FIGUREPERIMETER 388 #define EDIF_TOK_FIGUREWIDTH 389 #define EDIF_TOK_FILLPATTERN 390 #define EDIF_TOK_FOLLOW 391 #define EDIF_TOK_FORBIDDENEVENT 392 #define EDIF_TOK_GLOBALPORTREF 393 #define EDIF_TOK_GREATERTHAN 394 #define EDIF_TOK_GRIDMAP 395 #define EDIF_TOK_IGNORE 396 #define EDIF_TOK_INCLUDEFIGUREGROUP 397 #define EDIF_TOK_INITIAL 398 #define EDIF_TOK_INSTANCE 399 #define EDIF_TOK_INSTANCEBACKANNOTATE 400 #define EDIF_TOK_INSTANCEGROUP 401 #define EDIF_TOK_INSTANCEMAP 402 #define EDIF_TOK_INSTANCEREF 403 #define EDIF_TOK_INTEGER 404 #define EDIF_TOK_INTEGERDISPLAY 405 #define EDIF_TOK_INTERFACE 406 #define EDIF_TOK_INTERFIGUREGROUPSPACING 407 #define EDIF_TOK_INTERSECTION 408 #define EDIF_TOK_INTRAFIGUREGROUPSPACING 409 #define EDIF_TOK_INVERSE 410 #define EDIF_TOK_ISOLATED 411 #define EDIF_TOK_JOINED 412 #define EDIF_TOK_JUSTIFY 413 #define EDIF_TOK_KEYWORDDISPLAY 414 #define EDIF_TOK_KEYWORDLEVEL 415 #define EDIF_TOK_KEYWORDMAP 416 #define EDIF_TOK_LESSTHAN 417 #define EDIF_TOK_LIBRARY 418 #define EDIF_TOK_LIBRARYREF 419 #define EDIF_TOK_LISTOFNETS 420 #define EDIF_TOK_LISTOFPORTS 421 #define EDIF_TOK_LOADDELAY 422 #define EDIF_TOK_LOGICASSIGN 423 #define EDIF_TOK_LOGICINPUT 424 #define EDIF_TOK_LOGICLIST 425 #define EDIF_TOK_LOGICMAPINPUT 426 #define EDIF_TOK_LOGICMAPOUTPUT 427 #define EDIF_TOK_LOGICONEOF 428 #define EDIF_TOK_LOGICOUTPUT 429 #define EDIF_TOK_LOGICPORT 430 #define EDIF_TOK_LOGICREF 431 #define EDIF_TOK_LOGICVALUE 432 #define EDIF_TOK_LOGICWAVEFORM 433 #define EDIF_TOK_MAINTAIN 434 #define EDIF_TOK_MATCH 435 #define EDIF_TOK_MEMBER 436 #define EDIF_TOK_MINOMAX 437 #define EDIF_TOK_MINOMAXDISPLAY 438 #define EDIF_TOK_MNM 439 #define EDIF_TOK_MULTIPLEVALUESET 440 #define EDIF_TOK_MUSTJOIN 441 #define EDIF_TOK_NAME 442 #define EDIF_TOK_NET 443 #define EDIF_TOK_NETBACKANNOTATE 444 #define EDIF_TOK_NETBUNDLE 445 #define EDIF_TOK_NETDELAY 446 #define EDIF_TOK_NETGROUP 447 #define EDIF_TOK_NETMAP 448 #define EDIF_TOK_NETREF 449 #define EDIF_TOK_NOCHANGE 450 #define EDIF_TOK_NONPERMUTABLE 451 #define EDIF_TOK_NOTALLOWED 452 #define EDIF_TOK_NOTCHSPACING 453 #define EDIF_TOK_NUMBER 454 #define EDIF_TOK_NUMBERDEFINITION 455 #define EDIF_TOK_NUMBERDISPLAY 456 #define EDIF_TOK_OFFPAGECONNECTOR 457 #define EDIF_TOK_OFFSETEVENT 458 #define EDIF_TOK_OPENSHAPE 459 #define EDIF_TOK_ORIENTATION 460 #define EDIF_TOK_ORIGIN 461 #define EDIF_TOK_OVERHANGDISTANCE 462 #define EDIF_TOK_OVERLAPDISTANCE 463 #define EDIF_TOK_OVERSIZE 464 #define EDIF_TOK_OWNER 465 #define EDIF_TOK_PAGE 466 #define EDIF_TOK_PAGESIZE 467 #define EDIF_TOK_PARAMETER 468 #define EDIF_TOK_PARAMETERASSIGN 469 #define EDIF_TOK_PARAMETERDISPLAY 470 #define EDIF_TOK_PATH 471 #define EDIF_TOK_PATHDELAY 472 #define EDIF_TOK_PATHWIDTH 473 #define EDIF_TOK_PERMUTABLE 474 #define EDIF_TOK_PHYSICALDESIGNRULE 475 #define EDIF_TOK_PLUG 476 #define EDIF_TOK_POINT 477 #define EDIF_TOK_POINTDISPLAY 478 #define EDIF_TOK_POINTLIST 479 #define EDIF_TOK_POLYGON 480 #define EDIF_TOK_PORT 481 #define EDIF_TOK_PORTBACKANNOTATE 482 #define EDIF_TOK_PORTBUNDLE 483 #define EDIF_TOK_PORTDELAY 484 #define EDIF_TOK_PORTGROUP 485 #define EDIF_TOK_PORTIMPLEMENTATION 486 #define EDIF_TOK_PORTINSTANCE 487 #define EDIF_TOK_PORTLIST 488 #define EDIF_TOK_PORTLISTALIAS 489 #define EDIF_TOK_PORTMAP 490 #define EDIF_TOK_PORTREF 491 #define EDIF_TOK_PROGRAM 492 #define EDIF_TOK_PROPERTY 493 #define EDIF_TOK_PROPERTYDISPLAY 494 #define EDIF_TOK_PROTECTIONFRAME 495 #define EDIF_TOK_PT 496 #define EDIF_TOK_RANGEVECTOR 497 #define EDIF_TOK_RECTANGLE 498 #define EDIF_TOK_RECTANGLESIZE 499 #define EDIF_TOK_RENAME 500 #define EDIF_TOK_RESOLVES 501 #define EDIF_TOK_SCALE 502 #define EDIF_TOK_SCALEX 503 #define EDIF_TOK_SCALEY 504 #define EDIF_TOK_SECTION 505 #define EDIF_TOK_SHAPE 506 #define EDIF_TOK_SIMULATE 507 #define EDIF_TOK_SIMULATIONINFO 508 #define EDIF_TOK_SINGLEVALUESET 509 #define EDIF_TOK_SITE 510 #define EDIF_TOK_SOCKET 511 #define EDIF_TOK_SOCKETSET 512 #define EDIF_TOK_STATUS 513 #define EDIF_TOK_STEADY 514 #define EDIF_TOK_STRING 515 #define EDIF_TOK_STRINGDISPLAY 516 #define EDIF_TOK_STRONG 517 #define EDIF_TOK_SYMBOL 518 #define EDIF_TOK_SYMMETRY 519 #define EDIF_TOK_TABLE 520 #define EDIF_TOK_TABLEDEFAULT 521 #define EDIF_TOK_TECHNOLOGY 522 #define EDIF_TOK_TEXTHEIGHT 523 #define EDIF_TOK_TIMEINTERVAL 524 #define EDIF_TOK_TIMESTAMP 525 #define EDIF_TOK_TIMING 526 #define EDIF_TOK_TRANSFORM 527 #define EDIF_TOK_TRANSITION 528 #define EDIF_TOK_TRIGGER 529 #define EDIF_TOK_TRUE 530 #define EDIF_TOK_UNCONSTRAINED 531 #define EDIF_TOK_UNDEFINED 532 #define EDIF_TOK_UNION 533 #define EDIF_TOK_UNIT 534 #define EDIF_TOK_UNUSED 535 #define EDIF_TOK_USERDATA 536 #define EDIF_TOK_VERSION 537 #define EDIF_TOK_VIEW 538 #define EDIF_TOK_VIEWLIST 539 #define EDIF_TOK_VIEWMAP 540 #define EDIF_TOK_VIEWREF 541 #define EDIF_TOK_VIEWTYPE 542 #define EDIF_TOK_VISIBLE 543 #define EDIF_TOK_VOLTAGEMAP 544 #define EDIF_TOK_WAVEVALUE 545 #define EDIF_TOK_WEAK 546 #define EDIF_TOK_WEAKJOINED 547 #define EDIF_TOK_WHEN 548 #define EDIF_TOK_WRITTEN 549 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 1676 of yacc.c */ #line 193 "edif.y" char* s; pair_list* pl; str_pair* ps; /* Line 1676 of yacc.c */ #line 648 "edif.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE ediflval; pcb-4.2.2/src/data.h0000664000076400007640000000354113434555140011076 00000000000000/*! * \file src/data.h * * \brief Common identifiers. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_DATA_H #define PCB_DATA_H #include "global.h" /* --------------------------------------------------------------------------- * some shared identifiers */ extern CrosshairType Crosshair; extern MarkType Marked; extern OutputType Output; extern PCBType *PCB; #define max_group (PCB->Data->LayerN) #define max_copper_layer (PCB->Data->LayerN) #define bottom_silk_layer (max_copper_layer + BOTTOM_SILK_LAYER) #define top_silk_layer (max_copper_layer + TOP_SILK_LAYER) extern SettingType Settings; extern BufferType Buffers[MAX_BUFFER]; extern LibraryType Library; /*extern DeviceInfoType PrintingDevice[];*/ extern char *Progname; extern char *InputTranslations; extern int addedLines; extern int LayerStack[MAX_LAYER]; extern bool Bumped; extern FlagType no_flags; extern int netlist_frozen; #endif pcb-4.2.2/src/polygon.c0000664000076400007640000015201013533277055011651 00000000000000/*! * \file src/polygon.c * * \brief Special polygon editing routines. * * Here's a brief tour of the data and life of a polygon, courtesy of * Ben Jackson: * * A PCB PolygonType contains an array of points outlining the polygon. * This is what is manipulated by the UI and stored in the saved PCB. * * A PolygonType also contains a POLYAREA called 'Clipped' which is * computed dynamically by InitClip every time a board is loaded. * The point array is coverted to a POLYAREA by original_poly and then * holes are cut in it by clearPoly. * After that it is maintained dynamically as parts are added, moved or * removed (this is why sometimes bugs can be fixed by just re-loading * the board). * * A POLYAREA consists of a linked list of PLINE structures. * The head of that list is POLYAREA.contours. * The first contour is an outline of a filled region. * All of the subsequent PLINEs are holes cut out of that first contour. * POLYAREAs are in a doubly-linked list and each member of the list is * an independent (non-overlapping) area with its own outline and holes. * The function biggest() finds the largest POLYAREA so that * PolygonType.Clipped points to that shape. * The rest of the polygon still exists, it's just ignored when turning * the polygon into copper. * * The first POLYAREA in PolygonType.Clipped is what is used for the * vast majority of Polygon related tests. * The basic logic for an intersection is "is the target shape inside * POLYAREA.contours and NOT fully enclosed in any of * POLYAREA.contours.next... (the holes)". * * The polygon dicer (NoHolesPolygonDicer and r_NoHolesPolygonDicer) * emits a series of "simple" PLINE shapes. * That is, the PLINE isn't linked to any other "holes" oulines. * That's the meaning of the first test in r_NoHolesPolygonDicer. * It is testing to see if the PLINE contour (the first, making it a * solid outline) has a valid next pointer (which would point to one or * more holes). * The dicer works by recursively chopping the polygon in half through * the first hole it sees (which is guaranteed to eliminate at least * that one hole). * The dicer output is used for HIDs which cannot render things with * holes (which would require erasure). * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996,2010 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "global.h" #include "box.h" #include "create.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "error.h" #include "find.h" #include "misc.h" #include "move.h" #include "pcb-printf.h" #include "polygon.h" #include "remove.h" #include "rtree.h" #include "search.h" #include "set.h" #include "thermal.h" #include "undo.h" #ifdef HAVE_LIBDMALLOC #include #endif #define ROUND(x) ((long)(((x) >= 0 ? (x) + 0.5 : (x) - 0.5))) #define UNSUBTRACT_BLOAT 10 #define SUBTRACT_PIN_VIA_BATCH_SIZE 100 #define SUBTRACT_LINE_BATCH_SIZE 20 static double rotate_circle_seg[4]; void polygon_init (void) { double cos_ang = cos (2.0 * M_PI / POLY_CIRC_SEGS_F); double sin_ang = sin (2.0 * M_PI / POLY_CIRC_SEGS_F); rotate_circle_seg[0] = cos_ang; rotate_circle_seg[1] = -sin_ang; rotate_circle_seg[2] = sin_ang; rotate_circle_seg[3] = cos_ang; } Cardinal polygon_point_idx (PolygonType *polygon, PointType *point) { assert (point >= polygon->Points); assert (point <= polygon->Points + polygon->PointN); return ((char *)point - (char *)polygon->Points) / sizeof (PointType); } /*! * \brief Find contour number. * * 0 for outer, * * 1 for first hole etc.. */ Cardinal polygon_point_contour (PolygonType *polygon, Cardinal point) { Cardinal i; Cardinal contour = 0; for (i = 0; i < polygon->HoleIndexN; i++) if (point >= polygon->HoleIndex[i]) contour = i + 1; return contour; } Cardinal next_contour_point (PolygonType *polygon, Cardinal point) { Cardinal contour; Cardinal this_contour_start; Cardinal next_contour_start; contour = polygon_point_contour (polygon, point); this_contour_start = (contour == 0) ? 0 : polygon->HoleIndex[contour - 1]; next_contour_start = (contour == polygon->HoleIndexN) ? polygon->PointN : polygon->HoleIndex[contour]; /* Wrap back to the start of the contour we're in if we pass the end */ if (++point == next_contour_start) point = this_contour_start; return point; } Cardinal prev_contour_point (PolygonType *polygon, Cardinal point) { Cardinal contour; Cardinal prev_contour_end; Cardinal this_contour_end; contour = polygon_point_contour (polygon, point); prev_contour_end = (contour == 0) ? 0 : polygon->HoleIndex[contour - 1]; this_contour_end = (contour == polygon->HoleIndexN) ? polygon->PointN - 1: polygon->HoleIndex[contour] - 1; /* Wrap back to the start of the contour we're in if we pass the end */ if (point == prev_contour_end) point = this_contour_end; else point--; return point; } static void add_noholes_polyarea (PLINE *pline, void *user_data) { PolygonType *poly = (PolygonType *)user_data; /* Prepend the pline into the NoHoles linked list */ pline->next = poly->NoHoles; poly->NoHoles = pline; } void ComputeNoHoles (PolygonType *poly) { poly_FreeContours (&poly->NoHoles); if (poly->Clipped) NoHolesPolygonDicer (poly, NULL, add_noholes_polyarea, poly); else printf ("Compute_noholes caught poly->Clipped = NULL\n"); poly->NoHolesValid = 1; } static POLYAREA * biggest (POLYAREA * p) { POLYAREA *n, *top = NULL; PLINE *pl; rtree_t *tree; double big = -1; if (!p) return NULL; n = p; do { #if 0 if (n->contours->area < PCB->IsleArea) { n->b->f = n->f; n->f->b = n->b; poly_DelContour (&n->contours); if (n == p) p = n->f; n = n->f; if (!n->contours) { free (n); return NULL; } } #endif if (n->contours->area > big) { top = n; big = n->contours->area; } } while ((n = n->f) != p); assert (top); if (top == p) return p; pl = top->contours; tree = top->contour_tree; top->contours = p->contours; top->contour_tree = p->contour_tree; p->contours = pl; p->contour_tree = tree; assert (pl); assert (p->f); assert (p->b); return p; } POLYAREA * ContourToPoly (PLINE * contour) { POLYAREA *p; poly_PreContour (contour, TRUE); assert (contour->Flags.orient == PLF_DIR); if (!(p = poly_Create ())) return NULL; poly_InclContour (p, contour); assert (poly_Valid (p)); return p; } /*! * \brief Generate the basic polygon shape. * * This includes the perimeter of the polygon with any holes removed, but no * areas cleared by objects. * */ POLYAREA * original_poly (PolygonType * p) { PLINE *contour = NULL; POLYAREA *np = NULL; Cardinal n; Vector v; int hole = 0; /* If we can't create the structures, we can't do anything. */ if ((np = poly_Create ()) == NULL) return NULL; /* Iterate over every point in the array. Note that this includes both the * perimeter points and the points that define holes contours in the * polygon. The indices at which the points of each hole start are * recorded in the HoleIndex array. */ for (n = 0; n < p->PointN; n++) { /* No current contour? Make a new one starting at point */ /* (or) Add point to existing contour */ v[0] = p->Points[n].X; v[1] = p->Points[n].Y; if (contour == NULL) { /* This is the first VNODE in the contour, we need to initialize * the contour. * */ if ((contour = poly_NewContour (v)) == NULL) return NULL; /* Couldn't allocate memory*/ } else { /* Create a new VNODE at v, and insert it after head.prev */ poly_InclVertex (contour->head.prev, poly_CreateNode (v)); } /* Is current point last in contour (perimeter or hole)? * If so process it. * */ if (n == p->PointN - 1 /* last perimeter point */ /* or, last point of a hole contour.*/ || (hole < p->HoleIndexN && n == p->HoleIndex[hole] - 1)) { /* Process the contour */ poly_PreContour (contour, TRUE); /* make sure it is a positive contour (outer) or negative (hole) */ if (contour->Flags.orient != (hole ? PLF_INV : PLF_DIR)) poly_InvContour (contour); assert (contour->Flags.orient == (hole ? PLF_INV : PLF_DIR)); /* Insert the contour in the POLYAREA PLINE chain */ poly_InclContour (np, contour); assert (poly_Valid (np)); /* advance to the next hole contour and start over */ hole++; contour = NULL; } } return biggest (np); } POLYAREA * PolygonToPoly (PolygonType *p) { return original_poly (p); } POLYAREA * RectPoly (Coord x1, Coord x2, Coord y1, Coord y2) { PLINE *contour = NULL; Vector v; /* Return NULL for zero or negatively sized rectangles */ if (x2 <= x1 || y2 <= y1) return NULL; v[0] = x1; v[1] = y1; if ((contour = poly_NewContour (v)) == NULL) return NULL; v[0] = x2; v[1] = y1; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = x2; v[1] = y2; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = x1; v[1] = y2; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); return ContourToPoly (contour); } POLYAREA * OctagonPoly (Coord x, Coord y, Coord radius) { PLINE *contour = NULL; Vector v; v[0] = x + ROUND (radius * 0.5); v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2); if ((contour = poly_NewContour (v)) == NULL) return NULL; v[0] = x + ROUND (radius * TAN_22_5_DEGREE_2); v[1] = y + ROUND (radius * 0.5); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = x - (v[0] - x); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = x - ROUND (radius * 0.5); v[1] = y + ROUND (radius * TAN_22_5_DEGREE_2); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[1] = y - (v[1] - y); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = x - ROUND (radius * TAN_22_5_DEGREE_2); v[1] = y - ROUND (radius * 0.5); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = x - (v[0] - x); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = x + ROUND (radius * 0.5); v[1] = y - ROUND (radius * TAN_22_5_DEGREE_2); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); return ContourToPoly (contour); } /*! * \brief Add vertices in a fractional-circle starting from v * centered at X, Y and going counter-clockwise. * * Does not include the first point. * last argument is 1 for a full circle. * 2 for a half circle. * or 4 for a quarter circle. */ void frac_circle (PLINE * c, Coord X, Coord Y, Vector v, int fraction) { double e1, e2, t1; int i, range; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* move vector to origin */ e1 = (v[0] - X) * POLY_CIRC_RADIUS_ADJ; e2 = (v[1] - Y) * POLY_CIRC_RADIUS_ADJ; /* NB: the caller adds the last vertex, hence the -1 */ range = POLY_CIRC_SEGS / fraction - 1; for (i = 0; i < range; i++) { /* rotate the vector */ t1 = rotate_circle_seg[0] * e1 + rotate_circle_seg[1] * e2; e2 = rotate_circle_seg[2] * e1 + rotate_circle_seg[3] * e2; e1 = t1; v[0] = X + ROUND (e1); v[1] = Y + ROUND (e2); poly_InclVertex (c->head.prev, poly_CreateNode (v)); } } /*! * \brief Create a circle approximation from lines. */ POLYAREA * CirclePoly (Coord x, Coord y, Coord radius) { PLINE *contour; Vector v; if (radius <= 0) return NULL; v[0] = x + radius; v[1] = y; if ((contour = poly_NewContour (v)) == NULL) return NULL; frac_circle (contour, x, y, v, 1); contour->is_round = TRUE; contour->cx = x; contour->cy = y; contour->radius = radius; return ContourToPoly (contour); } /*! * \brief Make a rounded-corner rectangle with radius t beyond * x1,x2,y1,y2 rectangle. */ POLYAREA * RoundRect (Coord x1, Coord x2, Coord y1, Coord y2, Coord t) { PLINE *contour = NULL; Vector v; assert (x2 > x1); assert (y2 > y1); v[0] = x1 - t; v[1] = y1; if ((contour = poly_NewContour (v)) == NULL) return NULL; frac_circle (contour, x1, y1, v, 4); v[0] = x2; v[1] = y1 - t; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); frac_circle (contour, x2, y1, v, 4); v[0] = x2 + t; v[1] = y2; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); frac_circle (contour, x2, y2, v, 4); v[0] = x1; v[1] = y2 + t; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); frac_circle (contour, x1, y2, v, 4); return ContourToPoly (contour); } #define ARC_ANGLE 5 static POLYAREA * ArcPolyNoIntersect (ArcType * a, Coord thick) { PLINE *contour = NULL; POLYAREA *np = NULL; Vector v; BoxType *ends; int i, segs; double ang, da, rx, ry; long half; double radius_adj; if (thick <= 0) return NULL; if (a->Delta < 0) { a->StartAngle += a->Delta; a->Delta = -a->Delta; } half = (thick + 1) / 2; ends = GetArcEnds (a); /* start with inner radius */ rx = MAX (a->Width - half, 0); ry = MAX (a->Height - half, 0); segs = 1; if(thick > 0) segs = MAX (segs, a->Delta * M_PI / 360 * sqrt (hypot (rx, ry) / POLY_ARC_MAX_DEVIATION / 2 / thick)); segs = MAX(segs, a->Delta / ARC_ANGLE); ang = a->StartAngle; da = (1.0 * a->Delta) / segs; radius_adj = (M_PI*da/360)*(M_PI*da/360)/2; v[0] = a->X - rx * cos (ang * M180); v[1] = a->Y + ry * sin (ang * M180); if ((contour = poly_NewContour (v)) == NULL) return 0; for (i = 0; i < segs - 1; i++) { ang += da; v[0] = a->X - rx * cos (ang * M180); v[1] = a->Y + ry * sin (ang * M180); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); } /* find last point */ ang = a->StartAngle + a->Delta; v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj); v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj); /* add the round cap at the end */ frac_circle (contour, ends->X2, ends->Y2, v, 2); /* and now do the outer arc (going backwards) */ rx = (a->Width + half) * (1+radius_adj); ry = (a->Width + half) * (1+radius_adj); da = -da; for (i = 0; i < segs; i++) { v[0] = a->X - rx * cos (ang * M180); v[1] = a->Y + ry * sin (ang * M180); poly_InclVertex (contour->head.prev, poly_CreateNode (v)); ang += da; } /* now add other round cap */ ang = a->StartAngle; v[0] = a->X - rx * cos (ang * M180) * (1 - radius_adj); v[1] = a->Y + ry * sin (ang * M180) * (1 - radius_adj); frac_circle (contour, ends->X1, ends->Y1, v, 2); /* now we have the whole contour */ if (!(np = ContourToPoly (contour))) return NULL; return np; } #define MIN_CLEARANCE_BEFORE_BISECT 10. POLYAREA * ArcPoly (ArcType * a, Coord thick) { double delta; ArcType seg1, seg2; POLYAREA *tmp1, *tmp2, *res; delta = (a->Delta < 0) ? -a->Delta : a->Delta; /* If the arc segment would self-intersect, we need to construct it as the union of two non-intersecting segments */ if (2 * M_PI * a->Width * (1. - (double)delta / 360.) - thick < MIN_CLEARANCE_BEFORE_BISECT) { int half_delta = a->Delta / 2; seg1 = seg2 = *a; seg1.Delta = half_delta; seg2.Delta -= half_delta; seg2.StartAngle += half_delta; tmp1 = ArcPolyNoIntersect (&seg1, thick); tmp2 = ArcPolyNoIntersect (&seg2, thick); poly_Boolean_free (tmp1, tmp2, &res, PBO_UNITE); return res; } return ArcPolyNoIntersect (a, thick); } POLYAREA * LinePoly (LineType * L, Coord thick) { PLINE *contour = NULL; POLYAREA *np = NULL; Vector v; double d, dx, dy; long half;LineType _l=*L,*l=&_l; if (thick <= 0) return NULL; half = (thick + 1) / 2; d = hypot (l->Point1.X - l->Point2.X, l->Point1.Y - l->Point2.Y); if (!TEST_FLAG (SQUAREFLAG,l)) if (d == 0) /* line is a point */ return CirclePoly (l->Point1.X, l->Point1.Y, half); if (d != 0) { d = half / d; dx = (l->Point1.Y - l->Point2.Y) * d; dy = (l->Point2.X - l->Point1.X) * d; } else { dx = half; dy = 0; } if (TEST_FLAG (SQUAREFLAG,l))/* take into account the ends */ { l->Point1.X -= dy; l->Point1.Y += dx; l->Point2.X += dy; l->Point2.Y -= dx; } v[0] = l->Point1.X - dx; v[1] = l->Point1.Y - dy; if ((contour = poly_NewContour (v)) == NULL) return 0; v[0] = l->Point2.X - dx; v[1] = l->Point2.Y - dy; if (TEST_FLAG (SQUAREFLAG,l)) poly_InclVertex (contour->head.prev, poly_CreateNode (v)); else frac_circle (contour, l->Point2.X, l->Point2.Y, v, 2); v[0] = l->Point2.X + dx; v[1] = l->Point2.Y + dy; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); v[0] = l->Point1.X + dx; v[1] = l->Point1.Y + dy; if (TEST_FLAG (SQUAREFLAG,l)) poly_InclVertex (contour->head.prev, poly_CreateNode (v)); else frac_circle (contour, l->Point1.X, l->Point1.Y, v, 2); /* now we have the line contour */ if (!(np = ContourToPoly (contour))) return NULL; return np; } /*! * \brief Make a rounded-corner rectangle. */ POLYAREA * SquarePadPoly (PadType * pad, Coord clear) { PLINE *contour = NULL; POLYAREA *np = NULL; Vector v; double d; double tx, ty; double cx, cy; PadType _t=*pad,*t=&_t; PadType _c=*pad,*c=&_c; int halfthick = (pad->Thickness + 1) / 2; int halfclear = (clear + 1) / 2; d = hypot (pad->Point1.X - pad->Point2.X, pad->Point1.Y - pad->Point2.Y); if (d != 0) { double a = halfthick / d; tx = (t->Point1.Y - t->Point2.Y) * a; ty = (t->Point2.X - t->Point1.X) * a; a = halfclear / d; cx = (c->Point1.Y - c->Point2.Y) * a; cy = (c->Point2.X - c->Point1.X) * a; t->Point1.X -= ty; t->Point1.Y += tx; t->Point2.X += ty; t->Point2.Y -= tx; c->Point1.X -= cy; c->Point1.Y += cx; c->Point2.X += cy; c->Point2.Y -= cx; } else { tx = halfthick; ty = 0; cx = halfclear; cy = 0; t->Point1.Y += tx; t->Point2.Y -= tx; c->Point1.Y += cx; c->Point2.Y -= cx; } v[0] = c->Point1.X - tx; v[1] = c->Point1.Y - ty; if ((contour = poly_NewContour (v)) == NULL) return 0; frac_circle (contour, (t->Point1.X - tx), (t->Point1.Y - ty), v, 4); v[0] = t->Point2.X - cx; v[1] = t->Point2.Y - cy; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); frac_circle (contour, (t->Point2.X - tx), (t->Point2.Y - ty), v, 4); v[0] = c->Point2.X + tx; v[1] = c->Point2.Y + ty; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); frac_circle (contour, (t->Point2.X + tx), (t->Point2.Y + ty), v, 4); v[0] = t->Point1.X + cx; v[1] = t->Point1.Y + cy; poly_InclVertex (contour->head.prev, poly_CreateNode (v)); frac_circle (contour, (t->Point1.X + tx), (t->Point1.Y + ty), v, 4); /* now we have the line contour */ if (!(np = ContourToPoly (contour))) return NULL; return np; } /*! * \brief Clear np1 from the polygon. */ static int Subtract (POLYAREA * np1, PolygonType * p, bool fnp) { POLYAREA *merged = NULL, *np = np1; int x; assert (np); assert (p); if (!p->Clipped) /* polygon has no poly area, nothing to subtract from */ { if (fnp) poly_Free (&np); return 1; } assert (poly_Valid (p->Clipped)); assert (poly_Valid (np)); /* subtract the polyarea, using a boolean subtraction operation */ if (fnp) x = poly_Boolean_free (p->Clipped, np, &merged, PBO_SUB); else { x = poly_Boolean (p->Clipped, np, &merged, PBO_SUB); poly_Free (&p->Clipped); } assert (!merged || poly_Valid (merged)); if (x != err_ok) { fprintf (stderr, "Error while clipping PBO_SUB: %d\n", x); poly_Free (&merged); p->Clipped = NULL; if (p->NoHoles) printf ("Just leaked in Subtract\n"); p->NoHoles = NULL; return -1; } p->Clipped = biggest (merged); assert (!p->Clipped || poly_Valid (p->Clipped)); if (!p->Clipped) Message ("Polygon cleared out of existence near (%d, %d)\n", (p->BoundingBox.X1 + p->BoundingBox.X2) / 2, (p->BoundingBox.Y1 + p->BoundingBox.Y2) / 2); return 1; } /*! * \brief Create a polygon of the pin clearance. */ POLYAREA * PinPoly (PinType * pin, Coord thick, Coord clear) { int size; if (TEST_FLAG (SQUAREFLAG, pin)) { size = (thick + 1) / 2; return RoundRect (pin->X - size, pin->X + size, pin->Y - size, pin->Y + size, (clear + 1) / 2); } else { size = (thick + clear + 1) / 2; if (TEST_FLAG (OCTAGONFLAG, pin)) { return OctagonPoly (pin->X, pin->Y, size + size); } } return CirclePoly (pin->X, pin->Y, size); } POLYAREA * BoxPolyBloated (BoxType *box, Coord bloat) { return RectPoly (box->X1 - bloat, box->X2 + bloat, box->Y1 - bloat, box->Y2 + bloat); } /*! * \brief Remove the pin clearance from the polygon. */ static int SubtractPin (DataType * d, PinType * pin, LayerType * l, PolygonType * p) { POLYAREA *np; Cardinal i; if (pin->Clearance == 0) return 0; i = GetLayerNumber (d, l); if (TEST_THERM (i, pin)) { np = ThermPoly ((PCBType *) (d->pcb), pin, i); if (!np) return 0; } else { np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance); if (!np) return -1; } return Subtract (np, p, TRUE); } static int SubtractLine (LineType * line, PolygonType * p) { POLYAREA *np; if (!TEST_FLAG (CLEARLINEFLAG, line)) return 0; if (!(np = LinePoly (line, line->Thickness + line->Clearance))) return -1; return Subtract (np, p, true); } static int SubtractArc (ArcType * arc, PolygonType * p) { POLYAREA *np; if (!TEST_FLAG (CLEARLINEFLAG, arc)) return 0; if (!(np = ArcPoly (arc, arc->Thickness + arc->Clearance))) return -1; return Subtract (np, p, true); } static int SubtractText (TextType * text, PolygonType * p) { POLYAREA *np; const BoxType *b = &text->BoundingBox; if (!TEST_FLAG (CLEARLINEFLAG, text)) return 0; if (!(np = RoundRect (b->X1 + PCB->Bloat, b->X2 - PCB->Bloat, b->Y1 + PCB->Bloat, b->Y2 - PCB->Bloat, PCB->Bloat))) return -1; return Subtract (np, p, true); } static int SubtractPad (PadType * pad, PolygonType * p) { POLYAREA *np = NULL; if (pad->Clearance == 0) return 0; if (TEST_FLAG (SQUAREFLAG, pad)) { if (! (np = SquarePadPoly (pad, pad->Thickness + pad->Clearance))) return -1; } else { if (! (np = LinePoly ((LineType *) pad, pad->Thickness + pad->Clearance))) return -1; } return Subtract (np, p, true); } struct cpInfo { const BoxType *other; DataType *data; LayerType *layer; PolygonType *polygon; bool bottom; POLYAREA *accumulate; int batch_size; jmp_buf env; }; static void subtract_accumulated (struct cpInfo *info, PolygonType *polygon) { if (info->accumulate == NULL) return; Subtract (info->accumulate, polygon, true); info->accumulate = NULL; info->batch_size = 0; } static int pin_sub_callback (const BoxType * b, void *cl) { PinType *pin = (PinType *) b; struct cpInfo *info = (struct cpInfo *) cl; PolygonType *polygon; POLYAREA *np; POLYAREA *merged; Cardinal i; /* don't subtract the object that was put back! */ if (b == info->other) return 0; polygon = info->polygon; i = GetLayerNumber (info->data, info->layer); if (VIA_IS_BURIED (pin) && (!VIA_ON_LAYER (pin, i))) return 0; if (pin->Clearance == 0) return 0; if (TEST_THERM (i, pin)) { np = ThermPoly ((PCBType *) (info->data->pcb), pin, i); if (!np) return 1; } else { np = PinPoly (pin, PIN_SIZE (pin), pin->Clearance); if (!np) longjmp (info->env, 1); } poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE); info->accumulate = merged; info->batch_size ++; if (info->batch_size == SUBTRACT_PIN_VIA_BATCH_SIZE) subtract_accumulated (info, polygon); return 1; } static int arc_sub_callback (const BoxType * b, void *cl) { ArcType *arc = (ArcType *) b; struct cpInfo *info = (struct cpInfo *) cl; PolygonType *polygon; /* don't subtract the object that was put back! */ if (b == info->other) return 0; if (!TEST_FLAG (CLEARLINEFLAG, arc)) return 0; polygon = info->polygon; if (SubtractArc (arc, polygon) < 0) longjmp (info->env, 1); return 1; } static int pad_sub_callback (const BoxType * b, void *cl) { PadType *pad = (PadType *) b; struct cpInfo *info = (struct cpInfo *) cl; PolygonType *polygon; /* don't subtract the object that was put back! */ if (b == info->other) return 0; if (pad->Clearance == 0) return 0; polygon = info->polygon; if (XOR (TEST_FLAG (ONSOLDERFLAG, pad), !info->bottom)) { if (SubtractPad (pad, polygon) < 0) longjmp (info->env, 1); return 1; } return 0; } static int line_sub_callback (const BoxType * b, void *cl) { LineType *line = (LineType *) b; struct cpInfo *info = (struct cpInfo *) cl; PolygonType *polygon; POLYAREA *np; POLYAREA *merged; /* don't subtract the object that was put back! */ if (b == info->other) return 0; if (!TEST_FLAG (CLEARLINEFLAG, line)) return 0; polygon = info->polygon; if (!(np = LinePoly (line, line->Thickness + line->Clearance))) longjmp (info->env, 1); poly_Boolean_free (info->accumulate, np, &merged, PBO_UNITE); info->accumulate = merged; info->batch_size ++; if (info->batch_size == SUBTRACT_LINE_BATCH_SIZE) subtract_accumulated (info, polygon); return 1; } static int text_sub_callback (const BoxType * b, void *cl) { TextType *text = (TextType *) b; struct cpInfo *info = (struct cpInfo *) cl; PolygonType *polygon; /* don't subtract the object that was put back! */ if (b == info->other) return 0; if (!TEST_FLAG (CLEARLINEFLAG, text)) return 0; polygon = info->polygon; if (SubtractText (text, polygon) < 0) longjmp (info->env, 1); return 1; } static int Group (DataType *Data, Cardinal layer) { Cardinal i, j; for (i = 0; i < max_group; i++) for (j = 0; j < ((PCBType *) (Data->pcb))->LayerGroups.Number[i]; j++) if (layer == ((PCBType *) (Data->pcb))->LayerGroups.Entries[i][j]) return i; return i; } static int clearPoly (DataType *Data, LayerType *Layer, PolygonType * polygon, const BoxType * here, Coord expand) { int r = 0; BoxType region; struct cpInfo info; Cardinal group; if (!TEST_FLAG (CLEARPOLYFLAG, polygon) || GetLayerNumber (Data, Layer) >= max_copper_layer) return 0; group = Group (Data, GetLayerNumber (Data, Layer)); info.bottom = (group == Group (Data, bottom_silk_layer)); info.data = Data; info.other = here; info.layer = Layer; info.polygon = polygon; if (here) region = clip_box (here, &polygon->BoundingBox); else region = polygon->BoundingBox; region = bloat_box (®ion, expand); if (setjmp (info.env) == 0) { r = 0; info.accumulate = NULL; info.batch_size = 0; if (info.bottom || group == Group (Data, top_silk_layer)) r += r_search (Data->pad_tree, ®ion, NULL, pad_sub_callback, &info); GROUP_LOOP (Data, group); { r += r_search (layer->line_tree, ®ion, NULL, line_sub_callback, &info); subtract_accumulated (&info, polygon); r += r_search (layer->arc_tree, ®ion, NULL, arc_sub_callback, &info); r += r_search (layer->text_tree, ®ion, NULL, text_sub_callback, &info); } END_LOOP; r += r_search (Data->via_tree, ®ion, NULL, pin_sub_callback, &info); r += r_search (Data->pin_tree, ®ion, NULL, pin_sub_callback, &info); subtract_accumulated (&info, polygon); } polygon->NoHolesValid = 0; return r; } static int Unsubtract (POLYAREA * np1, PolygonType * p) { POLYAREA *merged = NULL, *np = np1; POLYAREA *orig_poly, *clipped_np; int x; assert (np); assert (p && p->Clipped); orig_poly = original_poly (p); x = poly_Boolean_free (np, orig_poly, &clipped_np, PBO_ISECT); if (x != err_ok) { fprintf (stderr, "Error while clipping PBO_ISECT: %d\n", x); poly_Free (&clipped_np); goto fail; } x = poly_Boolean_free (p->Clipped, clipped_np, &merged, PBO_UNITE); if (x != err_ok) { fprintf (stderr, "Error while clipping PBO_UNITE: %d\n", x); poly_Free (&merged); goto fail; } p->Clipped = biggest (merged); assert (!p->Clipped || poly_Valid (p->Clipped)); return 1; fail: p->Clipped = NULL; if (p->NoHoles) printf ("Just leaked in Unsubtract\n"); p->NoHoles = NULL; return 0; } static int UnsubtractPin (PinType * pin, LayerType * l, PolygonType * p) { POLYAREA *np; /* overlap a bit to prevent gaps from rounding errors */ np = BoxPolyBloated (&pin->BoundingBox, UNSUBTRACT_BLOAT); if (!np) return 0; if (!Unsubtract (np, p)) return 0; clearPoly (PCB->Data, l, p, (const BoxType *) pin, 2 * UNSUBTRACT_BLOAT); return 1; } static int UnsubtractArc (ArcType * arc, LayerType * l, PolygonType * p) { POLYAREA *np; if (!TEST_FLAG (CLEARLINEFLAG, arc)) return 0; /* overlap a bit to prevent gaps from rounding errors */ np = BoxPolyBloated (&arc->BoundingBox, UNSUBTRACT_BLOAT); if (!np) return 0; if (!Unsubtract (np, p)) return 0; clearPoly (PCB->Data, l, p, (const BoxType *) arc, 2 * UNSUBTRACT_BLOAT); return 1; } static int UnsubtractLine (LineType * line, LayerType * l, PolygonType * p) { POLYAREA *np; if (!TEST_FLAG (CLEARLINEFLAG, line)) return 0; /* overlap a bit to prevent notches from rounding errors */ np = BoxPolyBloated (&line->BoundingBox, UNSUBTRACT_BLOAT); if (!np) return 0; if (!Unsubtract (np, p)) return 0; clearPoly (PCB->Data, l, p, (const BoxType *) line, 2 * UNSUBTRACT_BLOAT); return 1; } static int UnsubtractText (TextType * text, LayerType * l, PolygonType * p) { POLYAREA *np; if (!TEST_FLAG (CLEARLINEFLAG, text)) return 0; /* overlap a bit to prevent notches from rounding errors */ np = BoxPolyBloated (&text->BoundingBox, UNSUBTRACT_BLOAT); if (!np) return -1; if (!Unsubtract (np, p)) return 0; clearPoly (PCB->Data, l, p, (const BoxType *) text, 2 * UNSUBTRACT_BLOAT); return 1; } static int UnsubtractPad (PadType * pad, LayerType * l, PolygonType * p) { POLYAREA *np; /* overlap a bit to prevent notches from rounding errors */ np = BoxPolyBloated (&pad->BoundingBox, UNSUBTRACT_BLOAT); if (!np) return 0; if (!Unsubtract (np, p)) return 0; clearPoly (PCB->Data, l, p, (const BoxType *) pad, 2 * UNSUBTRACT_BLOAT); return 1; } static bool inhibit = false; /*! * \brief Initialize low level polygon data structures. * */ int InitClip (DataType *Data, LayerType *layer, PolygonType * p) { if (inhibit) return 0; /* Clear any existing data. */ if (p->Clipped) poly_Free (&p->Clipped); /* Compute the perimeter of the polygon */ p->Clipped = original_poly (p); /* NoHoles is a version of the polygon broken into pieces so that it is * hole free. If we have one, we need to clear it. */ poly_FreeContours (&p->NoHoles); if (!p->Clipped) return 0; assert (poly_Valid (p->Clipped)); /* If the polygon is clearing, we need to add all of the object cutouts. */ if (TEST_FLAG (CLEARPOLYFLAG, p)) clearPoly (Data, layer, p, NULL, 0); else p->NoHolesValid = 0; return 1; } /*! * \brief Remove redundant polygon points. * * Any point that lies on the straight line between the points on either * side of it is redundant. * * \return True if any points are removed. */ bool RemoveExcessPolygonPoints (LayerType *Layer, PolygonType *Polygon) { PointType *p; Cardinal n, prev, next; LineType line; bool changed = false; if (Undoing ()) return (false); for (n = 0; n < Polygon->PointN; n++) { prev = prev_contour_point (Polygon, n); next = next_contour_point (Polygon, n); p = &Polygon->Points[n]; line.Point1 = Polygon->Points[prev]; line.Point2 = Polygon->Points[next]; line.Thickness = 0; if (IsPointOnLine (p->X, p->Y, 0.0, &line)) { RemoveObject (POLYGONPOINT_TYPE, Layer, Polygon, p); changed = true; } } return (changed); } /*! * \brief . * * \return The index of the polygon point which is the end point of the * segment with the lowest distance to the passed coordinates. */ Cardinal GetLowestDistancePolygonPoint (PolygonType *Polygon, Coord X, Coord Y) { double mindistance = (double) MAX_COORD * MAX_COORD; PointType *ptr1, *ptr2; Cardinal n, result = 0; /* we calculate the distance to each segment and choose the * shortest distance. If the closest approach between the * given point and the projected line (i.e. the segment extended) * is not on the segment, then the distance is the distance * to the segment end point. */ for (n = 0; n < Polygon->PointN; n++) { double u, dx, dy; ptr1 = &Polygon->Points[prev_contour_point (Polygon, n)]; ptr2 = &Polygon->Points[n]; dx = ptr2->X - ptr1->X; dy = ptr2->Y - ptr1->Y; if (dx != 0.0 || dy != 0.0) { /* projected intersection is at P1 + u(P2 - P1) */ u = ((X - ptr1->X) * dx + (Y - ptr1->Y) * dy) / (dx * dx + dy * dy); if (u < 0.0) { /* ptr1 is closest point */ u = SQUARE (X - ptr1->X) + SQUARE (Y - ptr1->Y); } else if (u > 1.0) { /* ptr2 is closest point */ u = SQUARE (X - ptr2->X) + SQUARE (Y - ptr2->Y); } else { /* projected intersection is closest point */ u = SQUARE (X - ptr1->X * (1.0 - u) - u * ptr2->X) + SQUARE (Y - ptr1->Y * (1.0 - u) - u * ptr2->Y); } if (u < mindistance) { mindistance = u; result = n; } } } return (result); } /*! * \brief Go back to the previous point of the polygon. */ void GoToPreviousPoint (void) { switch (Crosshair.AttachedPolygon.PointN) { /* do nothing if mode has just been entered */ case 0: break; /* reset number of points and 'LINE_MODE' state */ case 1: Crosshair.AttachedPolygon.PointN = 0; Crosshair.AttachedLine.State = STATE_FIRST; addedLines = 0; break; /* back-up one point */ default: { PointType *points = Crosshair.AttachedPolygon.Points; Cardinal n = Crosshair.AttachedPolygon.PointN - 2; Crosshair.AttachedPolygon.PointN--; Crosshair.AttachedLine.Point1.X = points[n].X; Crosshair.AttachedLine.Point1.Y = points[n].Y; break; } } } /*! * \brief Close polygon if possible. */ void ClosePolygon (void) { Cardinal n = Crosshair.AttachedPolygon.PointN; /* check number of points */ if (n >= 3) { /* if 45 degree lines are what we want do a quick check * if closing the polygon makes sense */ if (!TEST_FLAG (ALLDIRECTIONFLAG, PCB)) { Coord dx, dy; dx = abs (Crosshair.AttachedPolygon.Points[n - 1].X - Crosshair.AttachedPolygon.Points[0].X); dy = abs (Crosshair.AttachedPolygon.Points[n - 1].Y - Crosshair.AttachedPolygon.Points[0].Y); if (!(dx == 0 || dy == 0 || dx == dy)) { Message (_ ("Cannot close polygon because 45 degree lines are requested.\n")); return; } } CopyAttachedPolygonToLayer (); Draw (); } else Message (_("A polygon has to have at least 3 points\n")); } /*! * \brief Moves the data of the attached (new) polygon to the current * layer. */ void CopyAttachedPolygonToLayer (void) { PolygonType *polygon; int saveID; /* move data to layer and clear attached struct */ polygon = CreateNewPolygon (CURRENT, NoFlags ()); saveID = polygon->ID; *polygon = Crosshair.AttachedPolygon; polygon->ID = saveID; SET_FLAG (CLEARPOLYFLAG, polygon); if (TEST_FLAG (NEWFULLPOLYFLAG, PCB)) SET_FLAG (FULLPOLYFLAG, polygon); memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType)); SetPolygonBoundingBox (polygon); if (!CURRENT->polygon_tree) CURRENT->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (CURRENT->polygon_tree, (BoxType *) polygon, 0); InitClip (PCB->Data, CURRENT, polygon); DrawPolygon (CURRENT, polygon); SetChangedFlag (true); /* reset state of attached line */ Crosshair.AttachedLine.State = STATE_FIRST; addedLines = 0; /* add to undo list */ AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT, polygon, polygon); IncrementUndoSerialNumber (); } /*! * \brief Find polygon holes in range, then call the callback function * for each hole. * * If the callback returns non-zero, stop the search. */ int PolygonHoles (PolygonType *polygon, const BoxType *range, int (*callback) (PLINE *contour, void *user_data), void *user_data) { POLYAREA *pa = polygon->Clipped; PLINE *pl; /* If this hole is so big the polygon doesn't exist, then it's not * really a hole. */ if (!pa) return 0; for (pl = pa->contours->next; pl; pl = pl->next) { if (range != NULL && (pl->xmin > range->X2 || pl->xmax < range->X1 || pl->ymin > range->Y2 || pl->ymax < range->Y1)) continue; if (callback (pl, user_data)) { return 1; } } return 0; } struct plow_info { int type; void *ptr1, *ptr2; LayerType *layer; DataType *data; int (*callback) (DataType *, LayerType *, PolygonType *, int, void *, void *, void *); void *userdata; }; static int subtract_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon, int type, void *ptr1, void *ptr2, void *userdata) { PinType *via; int layer_n = GetLayerNumber (Data, Layer); if (!Polygon->Clipped) return 0; switch (type) { case PIN_TYPE: SubtractPin (Data, (PinType *) ptr2, Layer, Polygon); Polygon->NoHolesValid = 0; return 1; case VIA_TYPE: via = (PinType *) ptr2; if (!VIA_IS_BURIED (via) || VIA_ON_LAYER (via, layer_n)) { SubtractPin (Data, via, Layer, Polygon); Polygon->NoHolesValid = 0; return 1; } break; case LINE_TYPE: SubtractLine ((LineType *) ptr2, Polygon); Polygon->NoHolesValid = 0; return 1; case ARC_TYPE: SubtractArc ((ArcType *) ptr2, Polygon); Polygon->NoHolesValid = 0; return 1; case PAD_TYPE: SubtractPad ((PadType *) ptr2, Polygon); Polygon->NoHolesValid = 0; return 1; case TEXT_TYPE: SubtractText ((TextType *) ptr2, Polygon); Polygon->NoHolesValid = 0; return 1; } return 0; } static int add_plow (DataType *Data, LayerType *Layer, PolygonType *Polygon, int type, void *ptr1, void *ptr2, void *userdata) { PinType *via; int layer_n = GetLayerNumber (Data, Layer); switch (type) { case PIN_TYPE: UnsubtractPin ((PinType *) ptr2, Layer, Polygon); return 1; case VIA_TYPE: via = (PinType *) ptr2; if (!VIA_IS_BURIED (via) || VIA_ON_LAYER (via, layer_n)) { UnsubtractPin ((PinType *) ptr2, Layer, Polygon); return 1; } break; case LINE_TYPE: UnsubtractLine ((LineType *) ptr2, Layer, Polygon); return 1; case ARC_TYPE: UnsubtractArc ((ArcType *) ptr2, Layer, Polygon); return 1; case PAD_TYPE: UnsubtractPad ((PadType *) ptr2, Layer, Polygon); return 1; case TEXT_TYPE: UnsubtractText ((TextType *) ptr2, Layer, Polygon); return 1; } return 0; } static int plow_callback (const BoxType * b, void *cl) { struct plow_info *plow = (struct plow_info *) cl; PolygonType *polygon = (PolygonType *) b; if (TEST_FLAG (CLEARPOLYFLAG, polygon)) return plow->callback (plow->data, plow->layer, polygon, plow->type, plow->ptr1, plow->ptr2, plow->userdata); return 0; } int PlowsPolygon (DataType * Data, int type, void *ptr1, void *ptr2, int (*call_back) (DataType *data, LayerType *lay, PolygonType *poly, int type, void *ptr1, void *ptr2, void *userdata), void *userdata) { BoxType sb = ((PinType *) ptr2)->BoundingBox; int r = 0; struct plow_info info; info.type = type; info.ptr1 = ptr1; info.ptr2 = ptr2; info.data = Data; info.callback = call_back; info.userdata = userdata; switch (type) { case PIN_TYPE: case VIA_TYPE: if (type == PIN_TYPE || ptr1 == ptr2 || ptr1 == NULL) { LAYER_LOOP (Data, max_copper_layer); { info.layer = layer; r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); } END_LOOP; } else { GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data, ((LayerType *) ptr1)))); { info.layer = layer; r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); } END_LOOP; } break; case LINE_TYPE: case ARC_TYPE: case TEXT_TYPE: /* Don't test clearlineflag here because the DRC still needs to check * such objects. */ /* silk doesn't plow */ if (GetLayerNumber (Data, (LayerType *)ptr1) >= max_copper_layer) return 0; GROUP_LOOP (Data, GetLayerGroupNumberByNumber (GetLayerNumber (Data, ((LayerType *) ptr1)))); { info.layer = layer; r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); } END_LOOP; break; case PAD_TYPE: { Cardinal group = GetLayerGroupNumberByNumber ( TEST_FLAG (ONSOLDERFLAG, (PadType *) ptr2) ? bottom_silk_layer : top_silk_layer); GROUP_LOOP (Data, group); { info.layer = layer; r += r_search (layer->polygon_tree, &sb, NULL, plow_callback, &info); } END_LOOP; } break; case ELEMENT_TYPE: { PIN_LOOP ((ElementType *) ptr1); { PlowsPolygon (Data, PIN_TYPE, ptr1, pin, call_back, userdata); } END_LOOP; PAD_LOOP ((ElementType *) ptr1); { PlowsPolygon (Data, PAD_TYPE, ptr1, pad, call_back, userdata); } END_LOOP; } break; } return r; } void RestoreToPolygon (DataType * Data, int type, void *ptr1, void *ptr2) { if (!Data->polyClip) return; if (type == POLYGON_TYPE) InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2); else PlowsPolygon (Data, type, ptr1, ptr2, add_plow, NULL); } void ClearFromPolygon (DataType * Data, int type, void *ptr1, void *ptr2) { if (!Data->polyClip) return; if (type == POLYGON_TYPE) InitClip (PCB->Data, (LayerType *) ptr1, (PolygonType *) ptr2); else PlowsPolygon (Data, type, ptr1, ptr2, subtract_plow, NULL); } /*! * \brief Determine if a POLYAREA touches a polygon. * * if the third argument is true, this function will free the POLYAREA when * finished. * */ bool isects (POLYAREA * a, PolygonType *p, bool fr) { POLYAREA *x; bool ans; ans = Touching (a, p->Clipped); /* argument may be register, so we must copy it */ x = a; if (fr) poly_Free (&x); return ans; } /*! * \brief Determine if a point of radius r is inside a polygon. * */ bool IsPointInPolygon (Coord X, Coord Y, Coord r, PolygonType *p) { POLYAREA *c; Vector v; v[0] = X; v[1] = Y; /* If the center point is inside, then some part of the point must be too. */ if (poly_CheckInside (p->Clipped, v)) return true; /* if the center isn't inside, then the point has to have a non-zero * radius. * */ if (r < 1) return false; /* Create a circular POLYAREA of radius r, and see if it intersects. */ if (!(c = CirclePoly (X, Y, r))) return false; /* failed to create POLYAREA */ return isects (c, p, true); } bool IsPointInPolygonIgnoreHoles (Coord X, Coord Y, PolygonType *p) { Vector v; v[0] = X; v[1] = Y; return poly_InsideContour (p->Clipped->contours, v); } bool IsRectangleInPolygon (Coord X1, Coord Y1, Coord X2, Coord Y2, PolygonType *p) { POLYAREA *s; if (! (s = RectPoly (min (X1, X2), max (X1, X2), min (Y1, Y2), max (Y1, Y2)))) return false; return isects (s, p, true); } /*! * \brief . * * \note This function will free the passed POLYAREA. * It must only be passed a single POLYAREA (pa->f == pa->b == pa). */ static void r_NoHolesPolygonDicer (POLYAREA * pa, void (*emit) (PLINE *, void *), void *user_data) { PLINE *p = pa->contours; if (!pa->contours->next) /* no holes */ { pa->contours = NULL; /* The callback now owns the contour */ /* Don't bother removing it from the POLYAREA's rtree since we're going to free the POLYAREA below anyway */ emit (p, user_data); poly_Free (&pa); return; } else { POLYAREA *poly2, *left, *right; /* make a rectangle of the left region slicing through the middle of the first hole */ poly2 = RectPoly (p->xmin, (p->next->xmin + p->next->xmax) / 2, p->ymin, p->ymax); poly_AndSubtract_free (pa, poly2, &left, &right); if (left) { POLYAREA *cur, *next; cur = left; do { next = cur->f; cur->f = cur->b = cur; /* Detach this polygon piece */ r_NoHolesPolygonDicer (cur, emit, user_data); /* NB: The POLYAREA was freed by its use in the recursive dicer */ } while ((cur = next) != left); } if (right) { POLYAREA *cur, *next; cur = right; do { next = cur->f; cur->f = cur->b = cur; /* Detach this polygon piece */ r_NoHolesPolygonDicer (cur, emit, user_data); /* NB: The POLYAREA was freed by its use in the recursive dicer */ } while ((cur = next) != right); } } } void NoHolesPolygonDicer (PolygonType *p, const BoxType * clip, void (*emit) (PLINE *, void *), void *user_data) { POLYAREA *main_contour, *cur, *next; main_contour = poly_Create (); /* copy the main poly only */ poly_Copy1 (main_contour, p->Clipped); /* clip to the bounding box */ if (clip) { POLYAREA *cbox = RectPoly (clip->X1, clip->X2, clip->Y1, clip->Y2); poly_Boolean_free (main_contour, cbox, &main_contour, PBO_ISECT); } if (main_contour == NULL) return; /* Now dice it up. * NB: Could be more than one piece (because of the clip above) */ cur = main_contour; do { next = cur->f; cur->f = cur->b = cur; /* Detach this polygon piece */ r_NoHolesPolygonDicer (cur, emit, user_data); /* NB: The POLYAREA was freed by its use in the recursive dicer */ } while ((cur = next) != main_contour); } /*! * \brief Make a polygon split into multiple parts into multiple * polygons. */ bool MorphPolygon (LayerType *layer, PolygonType *poly) { POLYAREA *p, *start; bool many = false; FlagType flags; if (!poly->Clipped || TEST_FLAG (LOCKFLAG, poly)) return false; if (poly->Clipped->f == poly->Clipped) return false; ErasePolygon (poly); start = p = poly->Clipped; /* This is ugly. The creation of the new polygons can cause * all of the polygon pointers (including the one we're called * with to change if there is a realloc in GetPolygonMemory(). * That will invalidate our original "poly" argument, potentially * inside the loop. We need to steal the Clipped pointer and * hide it from the Remove call so that it still exists while * we do this dirty work. */ poly->Clipped = NULL; if (poly->NoHoles) printf ("Just leaked in MorpyPolygon\n"); poly->NoHoles = NULL; flags = poly->Flags; RemovePolygon (layer, poly); inhibit = true; do { VNODE *v; PolygonType *newone; if (p->contours->area > PCB->IsleArea) { newone = CreateNewPolygon (layer, flags); if (!newone) return false; many = true; v = &p->contours->head; CreateNewPointInPolygon (newone, v->point[0], v->point[1]); for (v = v->next; v != &p->contours->head; v = v->next) CreateNewPointInPolygon (newone, v->point[0], v->point[1]); newone->BoundingBox.X1 = p->contours->xmin; newone->BoundingBox.X2 = p->contours->xmax + 1; newone->BoundingBox.Y1 = p->contours->ymin; newone->BoundingBox.Y2 = p->contours->ymax + 1; AddObjectToCreateUndoList (POLYGON_TYPE, layer, newone, newone); newone->Clipped = p; p = p->f; /* go to next pline */ newone->Clipped->b = newone->Clipped->f = newone->Clipped; /* unlink from others */ r_insert_entry (layer->polygon_tree, (BoxType *) newone, 0); DrawPolygon (layer, newone); } else { POLYAREA *t = p; p = p->f; poly_DelContour (&t->contours); free (t); } } while (p != start); inhibit = false; IncrementUndoSerialNumber (); return many; } void debug_pline (PLINE *pl) { VNODE *v; pcb_fprintf (stderr, "\txmin %#mS xmax %#mS ymin %#mS ymax %#mS\n", pl->xmin, pl->xmax, pl->ymin, pl->ymax); v = &pl->head; while (v) { pcb_fprintf(stderr, "\t\tvnode: %#mD\n", v->point[0], v->point[1]); v = v->next; if (v == &pl->head) break; } } void debug_polyarea (POLYAREA *p) { PLINE *pl; fprintf (stderr, "POLYAREA %p\n", p); for (pl=p->contours; pl; pl=pl->next) debug_pline (pl); } void debug_polygon (PolygonType *p) { Cardinal i; POLYAREA *pa; fprintf (stderr, "POLYGON %p %d pts\n", p, p->PointN); for (i=0; iPointN; i++) pcb_fprintf(stderr, "\t%d: %#mD\n", i, p->Points[i].X, p->Points[i].Y); if (p->HoleIndexN) { fprintf (stderr, "%d holes, starting at indices\n", p->HoleIndexN); for (i=0; iHoleIndexN; i++) fprintf(stderr, "\t%d: %d\n", i, p->HoleIndex[i]); } else fprintf (stderr, "it has no holes\n"); pa = p->Clipped; while (pa) { debug_polyarea (pa); pa = pa->f; if (pa == p->Clipped) break; } } /*! * \brief Convert a POLYAREA (and all linked POLYAREA) to raw PCB * polygons on the given layer. */ void PolyToPolygonsOnLayer (DataType *Destination, LayerType *Layer, POLYAREA *Input, FlagType Flags) { PolygonType *Polygon; POLYAREA *pa; PLINE *pline; VNODE *node; bool outer; if (Input == NULL) return; pa = Input; do { Polygon = CreateNewPolygon (Layer, Flags); pline = pa->contours; outer = true; do { if (!outer) CreateNewHoleInPolygon (Polygon); outer = false; node = &pline->head; do { CreateNewPointInPolygon (Polygon, node->point[0], node->point[1]); } while ((node = node->next) != &pline->head); } while ((pline = pline->next) != NULL); InitClip (Destination, Layer, Polygon); SetPolygonBoundingBox (Polygon); if (!Layer->polygon_tree) Layer->polygon_tree = r_create_tree (NULL, 0, 0); r_insert_entry (Layer->polygon_tree, (BoxType *) Polygon, 0); DrawPolygon (Layer, Polygon); /* add to undo list */ AddObjectToCreateUndoList (POLYGON_TYPE, Layer, Polygon, Polygon); } while ((pa = pa->f) != Input); SetChangedFlag (true); } pcb-4.2.2/src/global.h0000664000076400007640000007254213533277055011442 00000000000000/*! * \file src/global.h * * \brief Definition of types. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996, 2004 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * *
* * Change History: * * 10/11/96 11:37 AJF Added support for a Text() driver function. * This was done out of a pressing need to force text to be printed on the * silkscreen layer. Perhaps the design is not the best. */ #ifndef PCB_GLOBAL_H #define PCB_GLOBAL_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "const.h" #include "macro.h" #include "flags.h" #include #ifdef HAVE_STDINT_H #include #endif #include #include #include #include #include #include #include #include #include #include /* Forward declarations for structures the HIDs need. */ typedef struct BoxType BoxType; typedef struct polygon_st PolygonType; typedef struct pad_st PadType; typedef struct pin_st PinType; typedef struct rtree rtree_t; typedef struct AttributeListType AttributeListType; typedef struct unit Unit; typedef struct increments Increments; typedef COORD_TYPE Coord; /*!< pcb base unit. */ typedef double Angle; /*!< Degrees. */ #include "hid.h" #include "polyarea.h" /* Internationalization support. */ #include "gettext.h" #if defined (ENABLE_NLS) /* When an empty string is used for msgid, the functions may return a nonempty string. */ # define _(S) (S[0] != '\0') ? gettext(S) : S # define N_(S) gettext_noop(S) # define C_(C, S) pgettext(C, S) #else # define _(S) S # define N_(S) S # define C_(C, S) S #endif /* ENABLE_NLS */ /*! * \brief This is used by the lexer/parser. */ typedef struct { int ival; Coord bval; double dval; char has_units; } PLMeasure; #ifndef XtSpecificationRelease typedef unsigned int Cardinal; /*typedef unsigned int Pixel;*/ typedef char *String; typedef short Position; typedef short Dimension; #endif typedef unsigned char BYTE; #ifndef __GNUC__ #define __FUNCTION1(a,b) a ":" #b #define __FUNCTION2(a,b) __FUNCTION1(a,b) #define __FUNCTION__ __FUNCTION2(__FILE__,__LINE__) #endif /* --------------------------------------------------------------------------- * Macros to annotate branch-prediction information. * Taken from GLib 2.16.3 (LGPL 2).G_ / g_ prefixes have * been removed to avoid namespace clashes. */ /* The LIKELY and UNLIKELY macros let the programmer give hints to * the compiler about the expected result of an expression. Some compilers * can use this information for optimizations. * * The PCB_BOOLEAN_EXPR macro is intended to trigger a gcc warning when * putting assignments inside the test. */ #if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) #define PCB_BOOLEAN_EXPR(expr) \ __extension__ ({ \ int _boolean_var_; \ if (expr) \ _boolean_var_ = 1; \ else \ _boolean_var_ = 0; \ _boolean_var_; \ }) #define LIKELY(expr) (__builtin_expect (PCB_BOOLEAN_EXPR(expr), 1)) #define UNLIKELY(expr) (__builtin_expect (PCB_BOOLEAN_EXPR(expr), 0)) #else #define LIKELY(expr) (expr) #define UNLIKELY(expr) (expr) #endif /* --------------------------------------------------------------------------- * Do not change the following definitions even if they're not very * nice. It allows us to have functions act on these "base types" and * not need to know what kind of actual object they're working on. */ /* Any object that uses the "object flags" defined in const.h, or exists as an object on the pcb, MUST be defined using this as the first fields, either directly or through ANYLINEFIELDS. */ #define ANYOBJECTFIELDS \ BoxType BoundingBox; \ long int ID; \ FlagType Flags; \ // struct LibraryEntryType *net /* Lines, pads, and rats all use this so they can be cross-cast. */ #define ANYLINEFIELDS \ ANYOBJECTFIELDS; \ Coord Thickness, \ Clearance; \ PointType Point1, \ Point2 /* --------------------------------------------------------------------------- * some useful values of our widgets */ /*! * \brief Holds information about output window. */ typedef struct { hidGC bgGC, /*!< Background; changed from some routines. */ fgGC, /*!< Foreground; changed from some routines. */ pmGC; /*!< Depth 1 pixmap GC to store clip. */ } OutputType; /*! * \brief Layer group. * * A layer group identifies layers which are always switched on/off * together. */ typedef struct { Cardinal Number[MAX_GROUP], /*!< Number of entries per groups. */ Entries[MAX_GROUP][MAX_ALL_LAYER]; } LayerGroupType; /*! * \brief A bounding box. */ struct BoxType { Coord X1, Y1; /*!< Upper left corner. */ Coord X2, Y2; /*!< Lower right corner. */ }; typedef struct { Coord x, y; Coord width, height; } RectangleType; typedef struct { char *name; char *value; } AttributeType; struct AttributeListType { int Number, Max; AttributeType *List; }; /* --------------------------------------------------------------------------- * the basic object types supported by PCB */ /*! * \brief All on-pcb objects (elements, lines, pads, vias, rats, etc) * are based on this. */ typedef struct { ANYOBJECTFIELDS; } AnyObjectType; /*! * \brief A line/polygon point. */ typedef struct { Coord X, Y, X2, Y2; /*!< So Point type can be cast as BoxType. */ long int ID; } PointType; /*! * \brief Lines, rats, pads, etc. */ typedef struct { ANYLINEFIELDS; } AnyLineObjectType; /*! * \brief Holds information about one line. */ typedef struct { ANYLINEFIELDS; char *Number; } LineType; typedef struct { ANYOBJECTFIELDS; int Scale; /*!< Text scaling in percent. */ Coord X; /*!< X-coordinate of origin. */ Coord Y; /*!< Y-coordinate of origin. */ BYTE Direction; char *TextString; /*!< String. */ void *Element; } TextType; /*! * \brief Holds information about a polygon. */ struct polygon_st { ANYOBJECTFIELDS; Cardinal PointN; /*!< Number of points in polygon. */ Cardinal PointMax; /*!< Max number from malloc(). */ POLYAREA *Clipped; /*!< The clipped region of this polygon. */ PLINE *NoHoles; /*!< The polygon broken into hole-less regions */ int NoHolesValid; /*!< Is the NoHoles polygon up to date? */ PointType *Points; /*!< Data. */ Cardinal *HoleIndex; /*!< Index of hole data within the Points array. */ Cardinal HoleIndexN; /*!< Number of holes in polygon. */ Cardinal HoleIndexMax; /*!< Max number from malloc(). */ }; /*! * \brief Holds information about arcs. */ typedef struct { ANYOBJECTFIELDS; Coord Thickness, Clearance; PointType Point1; PointType Point2; Coord Width; /*!< Length of axis */ Coord Height; /*!< Width of axis */ Coord X; /*!< X-value of the center coordinates. */ Coord Y; /*!< Y-value of the center coordinates. */ Angle StartAngle; /*!< The start angle in degrees. */ Angle Delta; /*!< The described angle in degrees. */ } ArcType; struct rtree { struct rtree_node *root; int size; /*!< Number of entries in tree */ }; /*! * \brief Holds information about one layer. */ typedef struct { LayertypeType Type; /*!< LT_* from hid.h */ char *Name; /*!< Layer name. */ Cardinal LineN; /*!< Number of lines. */ Cardinal TextN; /*!< Labels. */ Cardinal PolygonN; /*!< Polygons. */ Cardinal ArcN; /*!< Arcs. */ GList *Line; GList *Text; GList *Polygon; GList *Arc; rtree_t *line_tree, *text_tree, *polygon_tree, *arc_tree; bool On; /*!< Visible flag. */ char *Color, /*!< Color. */ *SelectedColor; AttributeListType Attributes; int no_drc; /*!< Whether to ignore the layer when checking the design rules */ } LayerType; /*! * \brief A rat line. */ typedef struct { ANYLINEFIELDS; Cardinal group1; /*!< The layer group each point is on. */ Cardinal group2; /*!< The layer group each point is on. */ } RatType; /*! * \brief A SMD pad. */ struct pad_st { ANYLINEFIELDS; Coord Mask; char *Name, *Number; /*!< 'Line'. */ void *Element; void *Spare; }; /*! * \brief A pin. */ struct pin_st { ANYOBJECTFIELDS; Coord Thickness; Coord Clearance; Coord Mask; Coord DrillingHole; /*!< Diameter of the drill hole. */ Coord X; /*!< X-value of the center coordinates. */ Coord Y; /*!< Y-value of the center coordinates. */ char *Name; char *Number; void *Element; void *Spare; Cardinal BuriedFrom; Cardinal BuriedTo; }; /* This is the extents of a Pin or Via, depending on whether it's a hole or not. */ #define PIN_SIZE(pinptr) (TEST_FLAG(HOLEFLAG, (pinptr)) \ ? (pinptr)->DrillingHole \ : (pinptr)->Thickness) /*! * \brief An element. */ typedef struct { ANYOBJECTFIELDS; TextType Name[MAX_ELEMENTNAMES]; /*!< The elements names; * - description text, * - name on PCB second, * - value third. * see macro.h. */ Coord MarkX; /*!< X-value of the position mark. */ Coord MarkY; /*!< Y-value of the position mark. */ Cardinal PinN; /*!< Number of pins. */ Cardinal PadN; /*!< Number of pads. */ Cardinal LineN; /*!< Number of lines. */ Cardinal ArcN; /*!< Number of arcs. */ GList *Pin; GList *Pad; GList *Line; GList *Arc; BoxType VBox; AttributeListType Attributes; } ElementType; /* --------------------------------------------------------------------------- * symbol and font related stuff */ /*! * \brief A single symbol. */ typedef struct { LineType *Line; bool Valid; Cardinal LineN; /*!< Number of lines. */ Cardinal LineMax; Coord Width; /*!< Width of cell. */ Coord Height; /*!< Height of cell. */ Coord Delta; /*!< Distance to next symbol. */ } SymbolType; /*! * \brief Complete set of symbols. */ typedef struct { Coord MaxHeight; /*!< Maximum cell width. */ Coord MaxWidth; /*!< Maximum cell height. */ BoxType DefaultSymbol; /*!< The default symbol is a filled box. */ SymbolType Symbol[MAX_FONTPOSITION + 1]; bool Valid; } FontType; /*! * \brief Holds all objects. */ typedef struct { Cardinal ViaN; /*!< Number of vias. */ Cardinal ElementN; /*!< Number of elements. */ Cardinal RatN; /*!< Number of rat-lines. */ int LayerN; /*!< Number of layers in this board. */ GList *Via; GList *Element; GList *Rat; rtree_t *via_tree, *element_tree, *pin_tree, *pad_tree, *name_tree[3], /* for element names */ *rat_tree; struct PCBType *pcb; LayerType Layer[MAX_ALL_LAYER]; int polyClip; } DataType; /*! * \brief Holds drill information. */ typedef struct { Coord DrillSize; /*!< This drill's diameter. */ Cardinal ElementN; /*!< The number of elements using this drill size. */ Cardinal ElementMax; /*!< Max. number of elements from malloc(). */ Cardinal PinCount; /*!< Number of pins drilled this size. */ Cardinal ViaCount; /*!< Number of vias drilled this size. */ Cardinal UnplatedCount; /*!< Number of these holes that are unplated. */ Cardinal PinN; /*!< Number of drill coordinates in the list. */ Cardinal PinMax; /*!< Max. number of coordinates from malloc(). */ PinType **Pin; /*!< Coordinates to drill. */ ElementType **Element; /*!< A pointer to an array of element pointers. */ } DrillType; /*! * \brief Holds a range of Drill Infos. */ typedef struct { Cardinal DrillN; /*!< Number of drill sizes. */ Cardinal DrillMax; /*!< Max. number from malloc(). */ DrillType *Drill; /*!< Plated holes. */ } DrillInfoType; typedef struct { Coord Thick; /*!< Line thickness. */ Coord Diameter; /*!< Via diameter. */ Coord Hole; /*!< Via drill hole. */ Coord ViaMask; /*!< Solder mask clearance. */ Coord Keepaway; /*!< Min. separation from other nets. */ char *Name; int index; } RouteStyleType; /*! * \brief Structure used by library routines. */ typedef struct { char *ListEntry; /*!< The string for the selection box. */ char *AllocatedMemory; /*!< Pointer to allocated memory; all others point to parts of the string. */ char *Template; /*!< m4 template name. */ char *Package; /*!< Package. */ char *Value; /*!< The value field. */ char *Description; /*!< Some descriptional text. */ } LibraryEntryType; /*! * \brief . * * If the internal flag is set, the only field that is valid is Name, * and the struct is allocated with malloc instead of * CreateLibraryEntry. These "internal" entries are used for * electrical paths that aren't yet assigned to a real net. */ typedef struct { char *Name; /*!< Name of the menu entry. */ char *directory; /*!< Directory name library elements are from. */ char *Style; /*!< Routing style. */ Cardinal EntryN; /*!< Number of objects. */ Cardinal EntryMax; /*!< Number of reserved memory locations. */ LibraryEntryType *Entry; /*!< The entries. */ char flag; /*!< Used by the netlist window to enable/disable nets. */ char internal; /*!< If set, this is an internal-only entry, not * part of the global netlist. */ } LibraryMenuType; typedef struct { Cardinal MenuN; /*!< Number of objects. */ Cardinal MenuMax; /*!< Number of reserved memory locations. */ LibraryMenuType *Menu; /*!< The entries. */ } LibraryType; /*! * \brief The PCBType struct holds information about board layout most * of which is saved with the layout. * * A new PCB layout struct is first initialized with values from the * user configurable \c Settings struct and then reset to the saved * layout values when a layout is loaded. * * This struct is also used for the remove list and for buffer handling. */ typedef struct PCBType { long ID; /*!< See macro.h. */ FlagType Flags; char *Name, /*!< Name of board. */ *Filename, /*!< Name of file (from load). */ *PrintFilename, /*!< From print dialog. */ *Netlistname, /*!< Name of netlist file. */ ThermStyle; /*!< Type of thermal to place with thermal tool. */ bool Changed, /*!< Layout has been changed. */ ViaOn, /*!< Visibility flag for vias. */ ElementOn, /*!< Visibility flag for elements. */ RatOn, /*!< Visibility flag for rat lines. */ InvisibleObjectsOn, PinOn, /*!< Visibility flag for pins. */ SilkActive, /*!< Active layer is actually silk. */ RatDraw; /*!< We're drawing rats. */ char *ViaColor, /*!< Via color. */ *ViaSelectedColor, /*!< Selected via color. */ *PinColor, /*!< Pin color. */ *PinSelectedColor, /*!< Selected pin color. */ *PinNameColor, /*!< Pin name color. */ *ElementColor, /*!< Element color. */ *RatColor, /*!< Rat line color. */ *InvisibleObjectsColor, /*!< Invisible objects color. */ *InvisibleMarkColor, /*!< Invisible mark color. */ *ElementSelectedColor, /*!< Selected elements color. */ *RatSelectedColor, /*!< Selected rat line color. */ *ConnectedColor, /*!< Connected color. */ *FoundColor, /*!< Found color. */ *WarnColor, /*!< Warning color. */ *MaskColor; /*!< Mask color. */ long CursorX, /*!< Cursor position as saved with layout (X value). */ CursorY, /*!< Cursor position as saved with layout (Y value). */ Clipping; Coord Bloat, /*!< DRC bloat size saved with layout. */ Shrink, /*!< DRC shrink size saved with layout. */ minWid, /*!< DRC minimum width size saved with layout. */ minSlk, /*!< DRC minimum silk size saved with layout. */ minDrill, /*!< DRC minimum drill size saved with layout. */ minRing; /*!< DRC minimum annular ring size saved with layout. */ Coord GridOffsetX, /*!< As saved with layout (X value). */ GridOffsetY, /*!< As saved with layout (Y value). */ MaxWidth, /*!< Maximum allowed width size. */ MaxHeight; /*!< Maximum allowed height size. */ Coord Grid; /*!< Used grid with offsets. */ double IsleArea, /*!< Minimum poly island to retain. */ ThermScale; /*!< Scale factor used with thermals. */ FontType Font; LayerGroupType LayerGroups; RouteStyleType RouteStyle[NUM_STYLES]; LibraryType NetlistLib; AttributeListType Attributes; DataType *Data; /*!< Entire database. */ bool is_footprint; /*!< If set, the user has loaded a footprint, not a pcb. */ } PCBType; /*! * \brief Information about the paste buffer. */ typedef struct { Coord X; /*!< Offset (X value). */ Coord Y; /*!< Offset (Y value). */ BoxType BoundingBox; DataType *Data; /*!< Data; not all members of PCBType are used. */ } BufferType; /* --------------------------------------------------------------------------- * some types for cursor drawing, setting of block and lines * as well as for merging of elements */ /*! * \brief Rubberband lines for element moves. */ typedef struct { LayerType *Layer; /*!< Layer that holds the line. */ LineType *Line; /*!< The line itself. */ PointType *MovedPoint; /*!< And finally the point. */ } RubberbandType; /*! * \brief Current marked line. */ typedef struct { PointType Point1; /*!< Start position. */ PointType Point2; /*!< End position. */ long int State; bool draw; } AttachedLineType; /*! * \brief Currently marked block. */ typedef struct { PointType Point1; /*!< Start position. */ PointType Point2; /*!< End position. */ long int State; bool otherway; } AttachedBoxType; /*! * \brief Currently attached object. */ typedef struct { Coord X; /*!< Saved position when MOVE_MODE (X value). */ Coord Y; /*!< Saved position when MOVE_MODE (Y value). */ BoxType BoundingBox; long int Type, /*!< Object type. */ State; void *Ptr1; /*!< Pointer to data, see search.c. */ void *Ptr2; /*!< Pointer to data, see search.c. */ void *Ptr3; /*!< Pointer to data, see search.c. */ Cardinal RubberbandN, /*!< Number of lines in array. */ RubberbandMax; RubberbandType *Rubberband; } AttachedObjectType; enum crosshair_shape { Basic_Crosshair_Shape = 0, /*!< 4-ray. */ Union_Jack_Crosshair_Shape, /*!< 8-ray. */ Dozen_Crosshair_Shape, /*!< 12-ray. */ Crosshair_Shapes_Number }; /*! * \brief Holds cursor information. */ typedef struct { hidGC GC; /*!< GC for cursor drawing. */ hidGC AttachGC; /*!< GC for displaying buffer contents. */ Coord X; /*!< Position in PCB coordinates (X value). */ Coord Y; /*!< Position in PCB coordinates (Y value). */ Coord MinX; /*!< Lowest coordinates (X value). */ Coord MinY; /*!< Lowest coordinates (Y value). */ Coord MaxX; /*!< Highest coordinates (X value). */ Coord MaxY; /*!< Highest coordinates (Y value). */ AttachedLineType AttachedLine; /*!< Data of new lines. */ AttachedBoxType AttachedBox; PolygonType AttachedPolygon; AttachedObjectType AttachedObject; /*!< Data of attached objects. */ enum crosshair_shape shape; /*!< Shape of Crosshair. */ } CrosshairType; typedef struct { bool status; Coord X, Y; } MarkType; /*! * \brief Our resources. * * Most of them are used as default when a new design is started. */ typedef struct { const Unit *grid_unit; Increments *increments; int verbose; char *BlackColor, *WhiteColor, *BackgroundColor, /*!< Background color. */ *CrosshairColor, /*!< Crosshair color. */ *CrossColor, /*!< Cross color. */ *ViaColor, /*!< Via color. */ *ViaSelectedColor, /*!< Selected via color. */ *PinColor, /*!< Pin color. */ *PinSelectedColor, /*!< Selected pin color. */ *PinNameColor, /*!< Pin name color. */ *ElementColor, /*!< Element color. */ *RatColor, /*!< Rat color. */ *InvisibleObjectsColor, /*!< Invisible objects color. */ *InvisibleMarkColor, /*!< Invisible mark color. */ *ElementSelectedColor, /*!< Selected element color. */ *RatSelectedColor, /*!< Selected rat color. */ *ConnectedColor, /*!< Connected color. */ *FoundColor, /*!< Found color. */ *OffLimitColor, *GridColor, /*!< Grid color. */ *LayerColor[MAX_LAYER], *LayerSelectedColor[MAX_LAYER], *WarnColor, /*!< Warning color. */ *MaskColor; /*!< Mask color. */ Coord ViaThickness, /*!< Default via thickness value. */ ViaDrillingHole, /*!< Default via drill hole value. */ ViaMaskAperture, /*!< Default solder mask aperture value. */ LineThickness, /*!< Default line thickness value. */ RatThickness, /*!< Default rat thickness value. */ Keepaway, /*!< Default keepaway value. */ MaxWidth, /*!< Default size of a new layout (X value). */ MaxHeight, /*!< Default size of a new layout (Y value). */ AlignmentDistance, Bloat, /*!< Default drc size for bloat. */ Shrink, /*!< Default drc size for shrink. */ minWid, /*!< Default drc size for minimum trace width. */ minSlk, /*!< Default drc size for minumum silk width. */ minDrill, /*!< Default drc size for minimum drill size. */ minRing; /*!< Default drc size for minimum annular ring. */ int TextScale; /*!< Text scaling in %. */ Coord Grid; /*!< Grid in pcb-units. */ double IsleArea; /*!< Polygon min area. */ Coord PasteAdjust; /*!< Paste adjustment. */ int PinoutNameLength, /*!< Max displayed length of a pinname. */ Volume, /*!< The speakers volume -100 .. 100. */ CharPerLine, /*!< Width of an output line in characters. */ Mode, /*!< Currently active mode. */ BufferNumber; /*!< Number of the current buffer. */ int BackupInterval; /*!< Time between two backups in seconds. */ char *DefaultLayerName[MAX_LAYER], *FontCommand, /*!< Command for font file loading. */ *FileCommand, /*!< Command for file loading. */ *ElementCommand, /*!< Command for element file loading. */ *PrintFile, *LibraryCommandDir, *LibraryCommand, *LibraryContentsCommand, *LibraryTree, /*!< Path to library tree. */ *SaveCommand, *LibraryFilename, *FontFile, /*!< Name of default font file. */ *Groups, /*!< String with layergroups. */ *Routes, /*!< String with route styles. */ *FilePath, *RatPath, *RatCommand, *FontPath, *PinoutFont, *ElementPath, *LibraryPath, *Size, /*!< Geometry string for size. */ *BackgroundImage, /*!< PPM file for board background. */ *ScriptFilename, /*!< PCB Actions script to execute on startup. */ *ActionString, /*!< PCB Actions string to execute on startup. */ *FabAuthor, /*!< Full name of author for FAB drawings. */ *GnetlistProgram, /*!< gnetlist program name. */ *MakeProgram, /*!< make program name. */ *InitialLayerStack; /*!< If set, the initial layer stack is set to this. */ Coord PinoutOffsetX; /*!< Offset of origin (X value). */ Coord PinoutOffsetY; /*!< Offset of origin (Y value). */ Coord PinoutTextOffsetX; /*!< Offset of text from pin center (X value). */ Coord PinoutTextOffsetY; /*!< Offset of text from pin center (Y value). */ RouteStyleType RouteStyle[NUM_STYLES]; /*!< Default routing styles. */ LayerGroupType LayerGroups; /*!< Default layer groups. */ bool ClearLine, FullPoly, UniqueNames, /*!< Force unique names. */ SnapPin, /*!< Snap to pins and pads. */ ShowBottomSide, /*!< Mirror output. */ SaveLastCommand, /*!< Save the last command entered by user. */ SaveInTMP, /*!< Always save data in /tmp. */ SaveMetricOnly, /*!< Save with mm suffix only, not mil/mm hybrid. */ DrawGrid, /*!< Draw grid points. */ RatWarn, /*!< Rats nest has set warnings. */ StipplePolygons, /*!< Draw polygons with stipple. */ AllDirectionLines, /*!< Enable lines to all directions. */ RubberBandMode, /*!< Move, rotate use rubberband connections. */ SwapStartDirection,/*!< Change starting direction after each click. */ ShowDRC, /*!< Show drc region on crosshair. */ AutoDRC, /*!< . */ ShowNumber, /*!< Pinout shows number. */ OrthogonalMoves, /*!< . */ ResetAfterElement, /*!< Reset connections after each element. */ liveRouting, /*!< Autorouter shows tracks in progress. */ AutoBuriedVias, RingBellWhenFinished, /*!< flag if a signal should be produced when searching of * connections is done. */ AutoPlace; /*!< Flag which says we should force placement of the windows on * startup. */ } SettingType; /*! * \brief Pointer to low-level copy, move and rotate functions. */ typedef struct { void *(*Line) (LayerType *, LineType *); void *(*Text) (LayerType *, TextType *); void *(*Polygon) (LayerType *, PolygonType *); void *(*Via) (PinType *); void *(*Element) (ElementType *); void *(*ElementName) (ElementType *); void *(*Pin) (ElementType *, PinType *); void *(*Pad) (ElementType *, PadType *); void *(*LinePoint) (LayerType *, LineType *, PointType *); void *(*Point) (LayerType *, PolygonType *, PointType *); void *(*Arc) (LayerType *, ArcType *); void *(*Rat) (RatType *); } ObjectFunctionType; /* --------------------------------------------------------------------------- * structure used by device drivers */ /*! * \brief Holds a connection. */ typedef struct { Coord X; /*!< Coordinate of connection (X value). */ Coord Y; /*!< Coordinate of connection (Y value). */ long int type; /*!< Type of object in ptr1 - 3. */ void *ptr1; /*!< The object of the connection. */ void *ptr2; /*!< The object of the connection. */ Cardinal group; /*!< The layer group of the connection. */ LibraryMenuType *menu; /*!< The netmenu this *SHOULD* belong to. */ } ConnectionType; /*! * \brief Holds a net of connections. */ typedef struct { Cardinal ConnectionN; /*!< The number of connections contained. */ Cardinal ConnectionMax; /*!< Max connections from malloc. */ ConnectionType *Connection; RouteStyleType *Style; } NetType; /*! * \brief Holds a list of nets. */ typedef struct { Cardinal NetN; /*!< The number of subnets contained. */ Cardinal NetMax; /*!< Max subnets from malloc. */ NetType *Net; } NetListType; /*! * \brief Holds a list of net lists. */ typedef struct { Cardinal NetListN; /*!< The number of net lists contained. */ Cardinal NetListMax; /*!< Max net lists from malloc. */ NetListType *NetList; } NetListListType; /*! * \brief Holds a generic list of pointers. */ typedef struct { Cardinal PtrN; /*!< The number of pointers contained. */ Cardinal PtrMax; /*!< Max subnets from malloc. */ void **Ptr; } PointerListType; typedef struct { Cardinal BoxN; /*!< The number of boxes contained. */ Cardinal BoxMax; /*!< Max boxes from malloc. */ BoxType *Box; } BoxListType; /* --------------------------------------------------------------------------- * define supported types of undo operations * note these must be separate bits now */ #define UNDO_CHANGENAME 0x0001 /*!< Change of names. */ #define UNDO_MOVE 0x0002 /*!< Moving objects. */ #define UNDO_REMOVE 0x0004 /*!< Removing objects. */ #define UNDO_REMOVE_POINT 0x0008 /*!< Removing polygon/... points. */ #define UNDO_INSERT_POINT 0x0010 /*!< Inserting polygon/... points. */ #define UNDO_REMOVE_CONTOUR 0x0020 /*!< Removing a contour from a polygon. */ #define UNDO_INSERT_CONTOUR 0x0040 /*!< Inserting a contour from a polygon. */ #define UNDO_ROTATE 0x0080 /*!< Rotations. */ #define UNDO_CREATE 0x0100 /*!< Creation of objects. */ #define UNDO_MOVETOLAYER 0x0200 /*!< Moving objects to. */ #define UNDO_FLAG 0x0400 /*!< Toggling SELECTED flag. */ #define UNDO_CHANGESIZE 0x0800 /*!< Change size of object. */ #define UNDO_CHANGE2NDSIZE 0x1000 /*!< Change 2ndSize of object. */ #define UNDO_MIRROR 0x2000 /*!< Change side of board. */ #define UNDO_CHANGECLEARSIZE 0x4000 /*!< Change clearance size. */ #define UNDO_CHANGEMASKSIZE 0x8000 /*!< Change mask size. */ #define UNDO_CHANGEANGLES 0x10000 /*!< Change arc angles. */ #define UNDO_LAYERCHANGE 0x20000 /*!< Layer new/delete/move. */ #define UNDO_CLEAR 0x40000 /*!< Clear/restore to polygons. */ #define UNDO_NETLISTCHANGE 0x80000 /*!< Netlist change. */ #define UNDO_CHANGESETVIALAYERS 0x100000 /*!< Buried data change. */ /* --------------------------------------------------------------------------- */ #if (__GNUC__ * 1000 + __GNUC_MINOR__) > 2007 #define ATTRIBUTE_UNUSED __attribute__((unused)) #else #define ATTRIBUTE_UNUSED #endif /* --------------------------------------------------------------------------- * Macros called by various action routines to show usage or to report * a syntax error and fail */ #define AUSAGE(x) Message (_("Usage:\n%s\n"), _(x##_syntax)) #define AFAIL(x) { Message (_("Syntax error. Usage:\n%s\n"), _(x##_syntax)); return 1; } /* --------------------------------------------------------------------------- * Variables with absolute paths to various directories. These are deduced * at runtime to allow pcb to be relocatable */ extern char *bindir; /*!< The dir in which PCB installation was found. */ extern char *pcblibdir; /*!< The system M4 fp directory. */ extern char *pcblibpath; /*!< The search path for M4 fps. */ extern char *pcbtreedir; /*!< The system newlib fp directory. */ extern char *pcbtreepath; /*!< The search path for newlib fps. */ extern char *exec_prefix; extern char *homedir; #endif /* PCB_GLOBAL_H */ pcb-4.2.2/src/intersect.h0000664000076400007640000000265713434555140012174 00000000000000/*! * \file src/intersect.h * * \brief Prototypes for rectangle intersection/union routines. * * \author this file, intersect.h, was written and is * Copyright (c) 2001 C. Scott Ananian. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu */ #ifndef PCB_INTERSECT_H #define PCB_INTERSECT_H #include "global.h" double ComputeIntersectionArea (BoxListType *boxlist); /* will sort boxlist */ double ComputeUnionArea (BoxListType *boxlist); #endif pcb-4.2.2/src/compat.h0000664000076400007640000000261013434555140011444 00000000000000/*! * \file src/compat.h * * \brief . * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2004 Dan McMahill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PCB_COMPAT_H #define PCB_COMPAT_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifndef HAVE_EXPF float expf (float); #endif #ifndef HAVE_LOGF float logf (float); #endif #ifndef HAVE_RANDOM long random (void); #endif #if !defined(HAVE_DLFCN_H) && defined(WIN32) void * dlopen (const char *, int); void dlclose (void *); char * dlerror (void); void * dlsym(void *, const char *); #define RTLD_NOW 2 #define RTLD_LOCAL 0 #define RTLD_GLOBAL 4 #endif #endif /* PCB_COMPAT_H */ pcb-4.2.2/src/autoplace.h0000664000076400007640000000250313434555140012137 00000000000000/*! * \file src/autoplace.h * * \brief Prototypes for autoplace routines. * * \author this file, autoplace.h, was written and is * Copyright (c) 2001 C. Scott Ananian. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu */ #ifndef PCB_AUTOPLACE_H #define PCB_AUTOPLACE_H #include "global.h" bool AutoPlaceSelected (void); #endif pcb-4.2.2/src/box.h0000664000076400007640000001420113434555140010750 00000000000000/*! * \file src/box.h * * \brief Random box-related utilities. * * \author This file, box.h, was written and is * Copyright (c) 2001 C. Scott Ananian. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu * */ #ifndef PCB_BOX_H #define PCB_BOX_H #include #include "global.h" #include "misc.h" typedef enum { NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3, NE = 4, SE = 5, SW = 6, NW = 7, ALL = 8 } direction_t; /*! * \brief Rotates box 90-degrees cw. * * That's a strange rotation! */ #define ROTATEBOX_CW(box) { Coord t;\ t = (box).X1; (box).X1 = -(box).Y2; (box).Y2 = (box).X2;\ (box).X2 = -(box).Y1; (box).Y1 = t;\ } #define ROTATEBOX_TO_NORTH(box, dir) do { Coord t;\ switch(dir) {\ case EAST: \ t = (box).X1; (box).X1 = (box).Y1; (box).Y1 = -(box).X2;\ (box).X2 = (box).Y2; (box).Y2 = -t; break;\ case SOUTH: \ t = (box).X1; (box).X1 = -(box).X2; (box).X2 = -t;\ t = (box).Y1; (box).Y1 = -(box).Y2; (box).Y2 = -t; break;\ case WEST: \ t = (box).X1; (box).X1 = -(box).Y2; (box).Y2 = (box).X2;\ (box).X2 = -(box).Y1; (box).Y1 = t; break;\ case NORTH: break;\ default: assert(0);\ }\ } while (0) #define ROTATEBOX_FROM_NORTH(box, dir) do { Coord t;\ switch(dir) {\ case WEST: \ t = (box).X1; (box).X1 = (box).Y1; (box).Y1 = -(box).X2;\ (box).X2 = (box).Y2; (box).Y2 = -t; break;\ case SOUTH: \ t = (box).X1; (box).X1 = -(box).X2; (box).X2 = -t;\ t = (box).Y1; (box).Y1 = -(box).Y2; (box).Y2 = -t; break;\ case EAST: \ t = (box).X1; (box).X1 = -(box).Y2; (box).Y2 = (box).X2;\ (box).X2 = -(box).Y1; (box).Y1 = t; break;\ case NORTH: break;\ default: assert(0);\ }\ } while (0) /* to avoid overflow, we calculate centers this way */ #define CENTER_X(b) ((b).X1 + ((b).X2 - (b).X1)/2) #define CENTER_Y(b) ((b).Y1 + ((b).Y2 - (b).Y1)/2) /* some useful box utilities. */ typedef struct cheap_point { Coord X, Y; } CheapPointType; /* note that boxes are closed on top and left and open on bottom and right. */ /* this means that top-left corner is in box, *but bottom-right corner is * not*. */ static inline bool point_in_box (const BoxType * box, Coord X, Coord Y) { return (X >= box->X1) && (Y >= box->Y1) && (X < box->X2) && (Y < box->Y2); } static inline bool point_in_closed_box (const BoxType * box, Coord X, Coord Y) { return (X >= box->X1) && (Y >= box->Y1) && (X <= box->X2) && (Y <= box->Y2); } static inline bool box_is_good (const BoxType * b) { return (b->X1 < b->X2) && (b->Y1 < b->Y2); } static inline bool box_intersect (const BoxType * a, const BoxType * b) { return (a->X1 < b->X2) && (b->X1 < a->X2) && (a->Y1 < b->Y2) && (b->Y1 < a->Y2); } static inline CheapPointType closest_point_in_box (const CheapPointType * from, const BoxType * box) { CheapPointType r; assert (box->X1 < box->X2 && box->Y1 < box->Y2); r.X = (from->X < box->X1) ? box->X1 : (from->X > box->X2 - 1) ? box->X2 - 1 : from->X; r.Y = (from->Y < box->Y1) ? box->Y1 : (from->Y > box->Y2 - 1) ? box->Y2 - 1 : from->Y; assert (point_in_box (box, r.X, r.Y)); return r; } static inline bool box_in_box (const BoxType * outer, const BoxType * inner) { return (outer->X1 <= inner->X1) && (inner->X2 <= outer->X2) && (outer->Y1 <= inner->Y1) && (inner->Y2 <= outer->Y2); } static inline BoxType clip_box (const BoxType * box, const BoxType * clipbox) { BoxType r; assert (box_intersect (box, clipbox)); r.X1 = MAX (box->X1, clipbox->X1); r.X2 = MIN (box->X2, clipbox->X2); r.Y1 = MAX (box->Y1, clipbox->Y1); r.Y2 = MIN (box->Y2, clipbox->Y2); assert (box_in_box (clipbox, &r)); return r; } static inline BoxType shrink_box (const BoxType * box, Coord amount) { BoxType r = *box; r.X1 += amount; r.Y1 += amount; r.X2 -= amount; r.Y2 -= amount; return r; } static inline BoxType bloat_box (const BoxType * box, Coord amount) { return shrink_box (box, -amount); } /*! * \brief Construct a minimum box that touches the input box at the * center. */ static inline BoxType box_center (const BoxType * box) { BoxType r; r.X1 = box->X1 + (box->X2 - box->X1)/2; r.X2 = r.X1 + 1; r.Y1 = box->Y1 + (box->Y2 - box->Y1)/2; r.Y2 = r.Y1 + 1; return r; } /*! * \brief Construct a minimum box that touches the input box at the * corner. */ static inline BoxType box_corner (const BoxType * box) { BoxType r; r.X1 = box->X1; r.X2 = r.X1 + 1; r.Y1 = box->Y1; r.Y2 = r.Y1 + 1; return r; } /*! * \brief Construct a box that holds a single point. */ static inline BoxType point_box (Coord X, Coord Y) { BoxType r; r.X1 = X; r.X2 = X + 1; r.Y1 = Y; r.Y2 = Y + 1; return r; } /*! * \brief Close a bounding box by pushing its upper right corner. */ static inline void close_box (BoxType * r) { r->X2++; r->Y2++; } /*! * \brief Return the square of the minimum distance from a point to some * point inside a box. * * The box is half-closed!\n * That is, the top-left corner is considered in the box, but the * bottom-right corner is not. */ static inline double dist2_to_box (const CheapPointType * p, const BoxType * b) { CheapPointType r = closest_point_in_box (p, b); return Distance (r.X, r.Y, p->X, p->Y); } #endif /* __BOX_H_INCLUDED__ */ pcb-4.2.2/src/action.c0000664000076400007640000063267413604156111011446 00000000000000/*! * \file src/action.c * * \brief Action routines for output window. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1997, 1998, 1999, 2000, 2001 Harry Eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Harry Eaton, 6697 Buttonhole Ct, Columbia, MD 21044, USA * haceaton@aplcomm.jhuapl.edu */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include "action.h" #include "autoplace.h" #include "autoroute.h" #include "buffer.h" #include "change.h" #include "copy.h" #include "create.h" #include "crosshair.h" #include "data.h" #include "draw.h" #include "error.h" #include "file.h" #include "find.h" #include "flags.h" #include "hid.h" #include "insert.h" #include "line.h" #include "mymem.h" #include "misc.h" #include "mirror.h" #include "move.h" #include "polygon.h" /*#include "print.h"*/ #include "rats.h" #include "remove.h" #include "report.h" #include "rotate.h" #include "rubberband.h" #include "search.h" #include "select.h" #include "set.h" #include "thermal.h" #include "undo.h" #include "rtree.h" #include "macro.h" #include "pcb-printf.h" #include #include /* rand() */ #ifdef HAVE_LIBDMALLOC #include #endif /* for fork() and friends */ #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif /* --------------------------------------------------------------------------- * some local types */ typedef enum { F_AddSelected, F_All, F_AllConnections, F_AllRats, F_AllUnusedPins, F_Arc, F_Arrow, F_Block, F_Description, F_Cancel, F_Center, F_Clear, F_ClearAndRedraw, F_ClearList, F_Close, F_Found, F_Connection, F_Convert, F_Copy, F_CycleClip, F_CycleCrosshair, F_DeleteRats, F_Drag, F_DrillReport, F_Element, F_ElementByName, F_ElementConnections, F_ElementToBuffer, F_Escape, F_Find, F_FlipElement, F_FoundPins, F_Grid, F_InsertPoint, F_Layer, F_Layout, F_LayoutAs, F_LayoutToBuffer, F_Line, F_LineSize, F_Lock, F_Mirror, F_Move, F_NameOnPCB, F_Netlist, F_NetByName, F_None, F_Notify, F_Object, F_ObjectByName, F_PasteBuffer, F_PadByName, F_PinByName, F_PinOrPadName, F_Pinout, F_Polygon, F_PolygonHole, F_PreviousPoint, F_RatsNest, F_Rectangle, F_Redraw, F_Release, F_Revert, F_Remove, F_RemoveSelected, F_Report, F_Reset, F_ResetLinesAndPolygons, F_ResetPinsViasAndPads, F_Restore, F_Rotate, F_Save, F_Selected, F_SelectedArcs, F_SelectedElements, F_SelectedLines, F_SelectedNames, F_SelectedObjects, F_SelectedPads, F_SelectedPins, F_SelectedTexts, F_SelectedVias, F_SelectedRats, F_Stroke, F_Text, F_TextByName, F_TextScale, F_Thermal, F_ToLayout, F_ToggleAllDirections, F_ToggleAutoDRC, F_ToggleClearLine, F_ToggleFullPoly, F_ToggleGrid, F_ToggleHideNames, F_ToggleMask, F_ToggleName, F_ToggleObject, F_ToggleShowDRC, F_ToggleLiveRoute, F_ToggleRubberBandMode, F_ToggleStartDirection, F_ToggleSnapPin, F_ToggleThindraw, F_ToggleLockNames, F_ToggleOnlyNames, F_ToggleThindrawPoly, F_ToggleOrthoMove, F_ToggleLocalRef, F_ToggleCheckPlanes, F_ToggleUniqueNames, F_Via, F_ViaByName, F_Value, F_ViaDrillingHole, F_ViaSize, F_Zoom, F_ThroughHole, F_BuriedVias, F_ToggleAutoBuriedVias } FunctionID; typedef struct /* used to identify subfunctions */ { char *Identifier; FunctionID ID; } FunctionType; /* --------------------------------------------------------------------------- */ /* %start-doc actions 00delta Many actions take a @code{delta} parameter as the last parameter, which is an amount to change something. That @code{delta} may include units, as an additional parameter, such as @code{Action(Object,5,mm)}. If no units are specified, the default is PCB's native units (currently 1/100 mil). Also, if the delta is prefixed by @code{+} or @code{-}, the size is increased or decreased by that amount. Otherwise, the size size is set to the given amount. @example Action(Object,5,mil) Action(Object,+0.5,mm) Action(Object,-1) @end example Actions which take a @code{delta} parameter which do not accept all these options will specify what they do take. %end-doc */ /* %start-doc actions 00objects Many actions act on indicated objects on the board. They will have parameters like @code{ToggleObject} or @code{SelectedVias} to indicate what group of objects they act on. Unless otherwise specified, these parameters are defined as follows: @table @code @item Object @itemx ToggleObject Affects the object under the mouse pointer. If this action is invoked from a menu or script, the user will be prompted to click on an object, which is then the object affected. @item Selected @itemx SelectedObjects Affects all objects which are currently selected. At least, all selected objects for which the given action makes sense. @item SelectedPins @itemx SelectedVias @itemx Selected@var{Type} @itemx @i{etc} Affects all objects which are both selected and of the @var{Type} specified. @end table %end-doc */ /* %start-doc actions 00macros @macro pinshapes Pins, pads, and vias can have various shapes. All may be round. Pins and pads may be square (obviously "square" pads are usually rectangular). Pins and vias may be octagonal. When you change a shape flag of an element, you actually change all of its pins and pads. Note that the square flag takes precedence over the octagon flag, thus, if both the square and octagon flags are set, the object is square. When the square flag is cleared, the pins and pads will be either round or, if the octagon flag is set, octagonal. @end macro %end-doc */ /* --------------------------------------------------------------------------- * some local identifiers */ static PointType InsertedPoint; static LayerType *lastLayer; static struct { PolygonType *poly; LineType line; } fake; static struct { Coord X, Y; Cardinal Buffer; bool Click; bool Moving; /* selected type clicked on */ int Hit; /* move type clicked on */ void *ptr1; void *ptr2; void *ptr3; } Note; static bool netlist_loaded; static int defer_updates = 0; static int defer_needs_update = 0; static Cardinal polyIndex = 0; static bool saved_mode = false; #ifdef HAVE_LIBSTROKE static bool mid_stroke = false; static BoxType StrokeBox; #endif static FunctionType Functions[] = { {"AddSelected", F_AddSelected}, {"All", F_All}, {"AllConnections", F_AllConnections}, {"AllRats", F_AllRats}, {"AllUnusedPins", F_AllUnusedPins}, {"Arc", F_Arc}, {"Arrow", F_Arrow}, {"Block", F_Block}, {"Description", F_Description}, {"Cancel", F_Cancel}, {"Center", F_Center}, {"Clear", F_Clear}, {"ClearAndRedraw", F_ClearAndRedraw}, {"ClearList", F_ClearList}, {"Close", F_Close}, {"Found", F_Found}, {"Connection", F_Connection}, {"Convert", F_Convert}, {"Copy", F_Copy}, {"CycleClip", F_CycleClip}, {"CycleCrosshair", F_CycleCrosshair}, {"DeleteRats", F_DeleteRats}, {"Drag", F_Drag}, {"DrillReport", F_DrillReport}, {"Element", F_Element}, {"ElementByName", F_ElementByName}, {"ElementConnections", F_ElementConnections}, {"ElementToBuffer", F_ElementToBuffer}, {"Escape", F_Escape}, {"Find", F_Find}, {"FlipElement", F_FlipElement}, {"FoundPins", F_FoundPins}, {"Grid", F_Grid}, {"InsertPoint", F_InsertPoint}, {"Layer", F_Layer}, {"Layout", F_Layout}, {"LayoutAs", F_LayoutAs}, {"LayoutToBuffer", F_LayoutToBuffer}, {"Line", F_Line}, {"LineSize", F_LineSize}, {"Lock", F_Lock}, {"Mirror", F_Mirror}, {"Move", F_Move}, {"NameOnPCB", F_NameOnPCB}, {"Netlist", F_Netlist}, {"NetByName", F_NetByName}, {"None", F_None}, {"Notify", F_Notify}, {"Object", F_Object}, {"ObjectByName", F_ObjectByName}, {"PasteBuffer", F_PasteBuffer}, {"PadByName", F_PadByName}, {"PinByName", F_PinByName}, {"PinOrPadName", F_PinOrPadName}, {"Pinout", F_Pinout}, {"Polygon", F_Polygon}, {"PolygonHole", F_PolygonHole}, {"PreviousPoint", F_PreviousPoint}, {"RatsNest", F_RatsNest}, {"Rectangle", F_Rectangle}, {"Redraw", F_Redraw}, {"Release", F_Release}, {"Remove", F_Remove}, {"RemoveSelected", F_RemoveSelected}, {"Report", F_Report}, {"Reset", F_Reset}, {"ResetLinesAndPolygons", F_ResetLinesAndPolygons}, {"ResetPinsViasAndPads", F_ResetPinsViasAndPads}, {"Restore", F_Restore}, {"Revert", F_Revert}, {"Rotate", F_Rotate}, {"Save", F_Save}, {"Selected", F_Selected}, {"SelectedArcs", F_SelectedArcs}, {"SelectedElements", F_SelectedElements}, {"SelectedLines", F_SelectedLines}, {"SelectedNames", F_SelectedNames}, {"SelectedObjects", F_SelectedObjects}, {"SelectedPins", F_SelectedPins}, {"SelectedPads", F_SelectedPads}, {"SelectedRats", F_SelectedRats}, {"SelectedTexts", F_SelectedTexts}, {"SelectedVias", F_SelectedVias}, {"Stroke", F_Stroke}, {"Text", F_Text}, {"TextByName", F_TextByName}, {"TextScale", F_TextScale}, {"Thermal", F_Thermal}, {"ToLayout", F_ToLayout}, {"Toggle45Degree", F_ToggleAllDirections}, {"ToggleClearLine", F_ToggleClearLine}, {"ToggleFullPoly", F_ToggleFullPoly}, {"ToggleGrid", F_ToggleGrid}, {"ToggleMask", F_ToggleMask}, {"ToggleName", F_ToggleName}, {"ToggleObject", F_ToggleObject}, {"ToggleRubberBandMode", F_ToggleRubberBandMode}, {"ToggleStartDirection", F_ToggleStartDirection}, {"ToggleSnapPin", F_ToggleSnapPin}, {"ToggleThindraw", F_ToggleThindraw}, {"ToggleThindrawPoly", F_ToggleThindrawPoly}, {"ToggleLockNames", F_ToggleLockNames}, {"ToggleOnlyNames", F_ToggleOnlyNames}, {"ToggleHideNames", F_ToggleHideNames}, {"ToggleCheckPlanes", F_ToggleCheckPlanes}, {"ToggleLocalRef", F_ToggleLocalRef}, {"ToggleOrthoMove", F_ToggleOrthoMove}, {"ToggleShowDRC", F_ToggleShowDRC}, {"ToggleLiveRoute", F_ToggleLiveRoute}, {"ToggleAutoDRC", F_ToggleAutoDRC}, {"ToggleUniqueNames", F_ToggleUniqueNames}, {"Value", F_Value}, {"Via", F_Via}, {"ViaByName", F_ViaByName}, {"ViaSize", F_ViaSize}, {"ViaDrillingHole", F_ViaDrillingHole}, {"Zoom", F_Zoom}, {"ThroughHole", F_ThroughHole}, {"TH", F_ThroughHole}, {"BuriedVias", F_BuriedVias}, {"ToggleAutoBuriedVias", F_ToggleAutoBuriedVias} }; /* --------------------------------------------------------------------------- * some local routines */ static int GetFunctionID (String); static void AdjustAttachedBox (void); static void NotifyLine (void); static void NotifyBlock (void); static void NotifyMode (void); static void ClearWarnings (void); #ifdef HAVE_LIBSTROKE static void FinishStroke (void); extern void stroke_init (void); extern void stroke_record (int x, int y); extern int stroke_trans (char *s); #endif static void ChangeFlag (char *, char *, int, char *); #ifdef HAVE_LIBSTROKE /*! * \brief Try to recognize the stroke sent. */ void FinishStroke (void) { char msg[255]; int type; unsigned long num; void *ptr1, *ptr2, *ptr3; mid_stroke = false; if (stroke_trans (msg)) { num = atoi (msg); switch (num) { case 456: if (Settings.Mode == LINE_MODE) { SetMode (LINE_MODE); } break; case 9874123: case 74123: case 987412: case 8741236: case 874123: RotateScreenObject (StrokeBox.X1, StrokeBox.Y1, SWAP_IDENT ? 1 : 3); break; case 7896321: case 786321: case 789632: case 896321: RotateScreenObject (StrokeBox.X1, StrokeBox.Y1, SWAP_IDENT ? 3 : 1); break; case 258: SetMode (LINE_MODE); break; case 852: SetMode (ARROW_MODE); break; case 1478963: ActionUndo (""); break; case 147423: case 147523: case 1474123: Redo (true); break; case 148963: case 147863: case 147853: case 145863: SetMode (VIA_MODE); break; case 951: case 9651: case 9521: case 9621: case 9851: case 9541: case 96521: case 96541: case 98541: /* XXX: FIXME: Call a zoom-extents action */ break; case 159: case 1269: case 1259: case 1459: case 1569: case 1589: case 12569: case 12589: case 14589: /* XXX: FIXME: Zoom to fit the box StrokeBox.[X1,Y1] - StrokeBox.[X2,Y2] */ break; default: Message (_("Unknown stroke %s\n"), msg); break; } } else gui->beep (); } #endif /*! * \brief Clear warning color from pins/pads. */ static void ClearWarnings () { Settings.RatWarn = false; ALLPIN_LOOP (PCB->Data); { if (TEST_FLAG (WARNFLAG, pin)) { CLEAR_FLAG (WARNFLAG, pin); DrawPin (pin); } } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { if (TEST_FLAG (WARNFLAG, pad)) { CLEAR_FLAG (WARNFLAG, pad); DrawPad (pad); } } ENDALL_LOOP; Draw (); } /*! * \brief Click callback. * * This is called a clicktime after a mouse down, to we can distinguish * between short clicks (typically: select or create something) and long * clicks. Long clicks typically drag something. */ static void click_cb (hidval hv) { if (Note.Click) { notify_crosshair_change (false); Note.Click = false; if (Note.Moving && !gui->shift_is_pressed ()) { Note.Buffer = Settings.BufferNumber; SetBufferNumber (MAX_BUFFER - 1); ClearBuffer (PASTEBUFFER); AddSelectedToBuffer (PASTEBUFFER, Note.X, Note.Y, true); SaveUndoSerialNumber (); RemoveSelected (); SaveMode (); saved_mode = true; SetMode (PASTEBUFFER_MODE); } else if (Note.Hit && !gui->shift_is_pressed ()) { SaveMode (); saved_mode = true; SetMode (gui->control_is_pressed ()? COPY_MODE : MOVE_MODE); Crosshair.AttachedObject.Ptr1 = Note.ptr1; Crosshair.AttachedObject.Ptr2 = Note.ptr2; Crosshair.AttachedObject.Ptr3 = Note.ptr3; Crosshair.AttachedObject.Type = Note.Hit; AttachForCopy (Note.X, Note.Y); } else { BoxType box; Note.Hit = 0; Note.Moving = false; SaveUndoSerialNumber (); box.X1 = -MAX_COORD; box.Y1 = -MAX_COORD; box.X2 = MAX_COORD; box.Y2 = MAX_COORD; /* unselect first if shift key not down */ if (!gui->shift_is_pressed () && SelectBlock (&box, false)) SetChangedFlag (true); NotifyBlock (); Crosshair.AttachedBox.Point1.X = Note.X; Crosshair.AttachedBox.Point1.Y = Note.Y; } notify_crosshair_change (true); } } /*! * \brief This is typically called when the mouse has moved or the mouse * button was released. */ static void ReleaseMode (void) { BoxType box; if (Note.Click) { BoxType box; box.X1 = -MAX_COORD; box.Y1 = -MAX_COORD; box.X2 = MAX_COORD; box.Y2 = MAX_COORD; Note.Click = false; /* inhibit timer action */ SaveUndoSerialNumber (); /* unselect first if shift key not down */ if (!gui->shift_is_pressed ()) { if (SelectBlock (&box, false)) SetChangedFlag (true); if (Note.Moving) { Note.Moving = 0; Note.Hit = 0; return; } } /* Restore the SN so that if we select something the deselect/select combo gets the same SN. */ RestoreUndoSerialNumber(); if (SelectObject ()) SetChangedFlag (true); else /* We didn't select anything new, so, the deselection should get its own SN. */ IncrementUndoSerialNumber(); Note.Hit = 0; Note.Moving = 0; } else if (Note.Moving) { RestoreUndoSerialNumber (); NotifyMode (); ClearBuffer (PASTEBUFFER); SetBufferNumber (Note.Buffer); Note.Moving = false; Note.Hit = 0; } else if (Note.Hit) { NotifyMode (); Note.Hit = 0; } else if (Settings.Mode == ARROW_MODE) { box.X1 = MIN (Crosshair.AttachedBox.Point1.X, Crosshair.AttachedBox.Point2.X); box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y, Crosshair.AttachedBox.Point2.Y); box.X2 = MAX (Crosshair.AttachedBox.Point1.X, Crosshair.AttachedBox.Point2.X); box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y, Crosshair.AttachedBox.Point2.Y); RestoreUndoSerialNumber (); if (SelectBlock (&box, true)) SetChangedFlag (true); else if (Bumped) IncrementUndoSerialNumber (); Crosshair.AttachedBox.State = STATE_FIRST; } if (saved_mode) RestoreMode (); saved_mode = false; } #define HSIZE 257 static char function_hash[HSIZE]; static int hash_initted = 0; static int hashfunc(String s) { int i = 0; while (*s) { i ^= i >> 16; i = (i * 13) ^ (unsigned char)tolower((int) *s); s ++; } i = (unsigned int)i % HSIZE; return i; } /*! * \brief Get function ID of passed string. */ static int GetFunctionID (String Ident) { int i, h; if (Ident == 0) return -1; if (!hash_initted) { hash_initted = 1; if (HSIZE < ENTRIES (Functions) * 2) { fprintf(stderr, _("Error: function hash size too small (%d vs %lu at %s:%d)\n"), HSIZE, (unsigned long) ENTRIES (Functions)*2, __FILE__, __LINE__); exit(1); } if (ENTRIES (Functions) > 254) { /* Change 'char' to 'int' and remove this when we get to 256 strings to hash. */ fprintf(stderr, _("Error: function hash type too small (%d vs %lu at %s:%d)\n"), 256, (unsigned long) ENTRIES (Functions), __FILE__, __LINE__); exit(1); } for (i=ENTRIES (Functions)-1; i>=0; i--) { h = hashfunc (Functions[i].Identifier); while (function_hash[h]) h = (h + 1) % HSIZE; function_hash[h] = i + 1; } } i = hashfunc (Ident); while (1) { /* We enforce the "hash table bigger than function table" rule, so we know there will be at least one zero entry to find. */ if (!function_hash[i]) return (-1); if (!strcasecmp (Ident, Functions[function_hash[i]-1].Identifier)) return ((int) Functions[function_hash[i]-1].ID); i = (i + 1) % HSIZE; } } /*! * \brief Set new coordinates if in 'RECTANGLE' mode. * * The cursor shape is also adjusted. */ static void AdjustAttachedBox (void) { if (Settings.Mode == ARC_MODE) { Crosshair.AttachedBox.otherway = gui->shift_is_pressed (); return; } switch (Crosshair.AttachedBox.State) { case STATE_SECOND: /* one corner is selected */ { /* update coordinates */ Crosshair.AttachedBox.Point2.X = Crosshair.X; Crosshair.AttachedBox.Point2.Y = Crosshair.Y; break; } } } /*! * \brief Adjusts the objects which are to be created like attached * lines. */ void AdjustAttachedObjects (void) { PointType *pnt; switch (Settings.Mode) { /* update at least an attached block (selection) */ case NO_MODE: case ARROW_MODE: if (Crosshair.AttachedBox.State) { Crosshair.AttachedBox.Point2.X = Crosshair.X; Crosshair.AttachedBox.Point2.Y = Crosshair.Y; } break; /* rectangle creation mode */ case RECTANGLE_MODE: case ARC_MODE: AdjustAttachedBox (); break; /* polygon creation mode */ case POLYGON_MODE: case POLYGONHOLE_MODE: AdjustAttachedLine (); break; /* line creation mode */ case LINE_MODE: if (PCB->RatDraw || PCB->Clipping == 0) AdjustAttachedLine (); else AdjustTwoLine (PCB->Clipping - 1); break; /* point insertion mode */ case INSERTPOINT_MODE: pnt = AdjustInsertPoint (); if (pnt) InsertedPoint = *pnt; break; case ROTATE_MODE: break; } } /*! * \brief Creates points of a line. */ static void NotifyLine (void) { int type = NO_TYPE; void *ptr1, *ptr2, *ptr3; if (!Marked.status || TEST_FLAG (LOCALREFFLAG, PCB)) SetLocalRef (Crosshair.X, Crosshair.Y, true); switch (Crosshair.AttachedLine.State) { case STATE_FIRST: /* first point */ if (PCB->RatDraw && SearchScreen (Crosshair.X, Crosshair.Y, PAD_TYPE | PIN_TYPE, &ptr1, &ptr1, &ptr1) == NO_TYPE) { gui->beep (); break; } if (TEST_FLAG (AUTODRCFLAG, PCB) && Settings.Mode == LINE_MODE) { type = SearchScreen (Crosshair.X, Crosshair.Y, PIN_TYPE | PAD_TYPE | VIA_TYPE, &ptr1, &ptr2, &ptr3); LookupConnection (Crosshair.X, Crosshair.Y, true, 1, CONNECTEDFLAG, false); LookupConnection (Crosshair.X, Crosshair.Y, true, 1, FOUNDFLAG, true); } if (type == PIN_TYPE || type == VIA_TYPE) { Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X = ((PinType *) ptr2)->X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y = ((PinType *) ptr2)->Y; } else if (type == PAD_TYPE) { PadType *pad = (PadType *) ptr2; double d1 = Distance (Crosshair.X, Crosshair.Y, pad->Point1.X, pad->Point1.Y); double d2 = Distance (Crosshair.X, Crosshair.Y, pad->Point2.X, pad->Point2.Y); if (d2 < d1) { Crosshair.AttachedLine.Point1 = Crosshair.AttachedLine.Point2 = pad->Point2; } else { Crosshair.AttachedLine.Point1 = Crosshair.AttachedLine.Point2 = pad->Point1; } } else { Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X = Crosshair.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y = Crosshair.Y; } Crosshair.AttachedLine.State = STATE_SECOND; break; case STATE_SECOND: /* fall through to third state too */ lastLayer = CURRENT; default: /* all following points */ Crosshair.AttachedLine.State = STATE_THIRD; break; } } /*! * \brief Create first or second corner of a marked block. */ static void NotifyBlock (void) { notify_crosshair_change (false); switch (Crosshair.AttachedBox.State) { case STATE_FIRST: /* setup first point */ Crosshair.AttachedBox.Point1.X = Crosshair.AttachedBox.Point2.X = Crosshair.X; Crosshair.AttachedBox.Point1.Y = Crosshair.AttachedBox.Point2.Y = Crosshair.Y; Crosshair.AttachedBox.State = STATE_SECOND; break; case STATE_SECOND: /* setup second point */ Crosshair.AttachedBox.State = STATE_THIRD; break; } notify_crosshair_change (true); } /*! * \brief This is called after every mode change, like mouse button pressed, * mouse button released, dragging something started or a different tool * selected. * * It does what's appropriate for the current mode setting. * This can also mean creation of an object at the current crosshair location. * * New created objects are added to the create undo list of course. */ static void NotifyMode (void) { void *ptr1, *ptr2, *ptr3; int type; if (Settings.RatWarn) ClearWarnings (); switch (Settings.Mode) { case ARROW_MODE: { int test; hidval hv; Note.Click = true; /* do something after click time */ gui->add_timer (click_cb, CLICK_TIME, hv); /* see if we clicked on something already selected * (Note.Moving) or clicked on a MOVE_TYPE * (Note.Hit) */ for (test = (SELECT_TYPES | MOVE_TYPES) & ~RATLINE_TYPE; test; test &= ~type) { type = SearchScreen (Note.X, Note.Y, test, &ptr1, &ptr2, &ptr3); if (!Note.Hit && (type & MOVE_TYPES) && !TEST_FLAG (LOCKFLAG, (PinType *) ptr2)) { Note.Hit = type; Note.ptr1 = ptr1; Note.ptr2 = ptr2; Note.ptr3 = ptr3; } if (!Note.Moving && (type & SELECT_TYPES) && TEST_FLAG (SELECTEDFLAG, (PinType *) ptr2)) Note.Moving = true; if ((Note.Hit && Note.Moving) || type == NO_TYPE) break; } break; } case VIA_MODE: { PinType *via; if (!PCB->ViaOn) { Message (_("You must turn via visibility on before\n" "you can place vias\n")); break; } if ((via = CreateNewVia (PCB->Data, Note.X, Note.Y, Settings.ViaThickness, 2 * Settings.Keepaway, Settings.ViaMaskAperture, Settings.ViaDrillingHole, NULL, NoFlags ())) != NULL) { AddObjectToCreateUndoList (VIA_TYPE, via, via, via); if (gui->shift_is_pressed ()) ChangeObjectThermal (VIA_TYPE, via, via, via, PCB->ThermStyle); IncrementUndoSerialNumber (); DrawVia (via); Draw (); } break; } case ARC_MODE: { switch (Crosshair.AttachedBox.State) { case STATE_FIRST: Crosshair.AttachedBox.Point1.X = Crosshair.AttachedBox.Point2.X = Note.X; Crosshair.AttachedBox.Point1.Y = Crosshair.AttachedBox.Point2.Y = Note.Y; Crosshair.AttachedBox.State = STATE_SECOND; break; case STATE_SECOND: case STATE_THIRD: { ArcType *arc; Coord wx, wy; Angle sa, dir; wx = Note.X - Crosshair.AttachedBox.Point1.X; wy = Note.Y - Crosshair.AttachedBox.Point1.Y; if (XOR (Crosshair.AttachedBox.otherway, abs (wy) > abs (wx))) { Crosshair.AttachedBox.Point2.X = Crosshair.AttachedBox.Point1.X + abs (wy) * SGNZ (wx); sa = (wx >= 0) ? 0 : 180; #ifdef ARC45 if (abs (wy) / 2 >= abs (wx)) dir = (SGNZ (wx) == SGNZ (wy)) ? 45 : -45; else #endif dir = (SGNZ (wx) == SGNZ (wy)) ? 90 : -90; } else { Crosshair.AttachedBox.Point2.Y = Crosshair.AttachedBox.Point1.Y + abs (wx) * SGNZ (wy); sa = (wy >= 0) ? -90 : 90; #ifdef ARC45 if (abs (wx) / 2 >= abs (wy)) dir = (SGNZ (wx) == SGNZ (wy)) ? -45 : 45; else #endif dir = (SGNZ (wx) == SGNZ (wy)) ? -90 : 90; wy = wx; } if (abs (wy) > 0 && (arc = CreateNewArcOnLayer (CURRENT, Crosshair. AttachedBox. Point2.X, Crosshair. AttachedBox. Point2.Y, abs (wy), abs (wy), sa, dir, Settings. LineThickness, 2 * Settings. Keepaway, MakeFlags (TEST_FLAG (CLEARNEWFLAG, PCB) ? CLEARLINEFLAG : 0)))) { BoxType *bx; bx = GetArcEnds (arc); Crosshair.AttachedBox.Point1.X = Crosshair.AttachedBox.Point2.X = bx->X2; Crosshair.AttachedBox.Point1.Y = Crosshair.AttachedBox.Point2.Y = bx->Y2; AddObjectToCreateUndoList (ARC_TYPE, CURRENT, arc, arc); IncrementUndoSerialNumber (); addedLines++; DrawArc (CURRENT, arc); Draw (); Crosshair.AttachedBox.State = STATE_THIRD; } break; } } break; } case LOCK_MODE: { type = SearchScreen (Note.X, Note.Y, LOCK_TYPES, &ptr1, &ptr2, &ptr3); if (type == ELEMENT_TYPE) { ElementType *element = (ElementType *) ptr2; TOGGLE_FLAG (LOCKFLAG, element); PIN_LOOP (element); { TOGGLE_FLAG (LOCKFLAG, pin); CLEAR_FLAG (SELECTEDFLAG, pin); } END_LOOP; PAD_LOOP (element); { TOGGLE_FLAG (LOCKFLAG, pad); CLEAR_FLAG (SELECTEDFLAG, pad); } END_LOOP; CLEAR_FLAG (SELECTEDFLAG, element); /* always re-draw it since I'm too lazy * to tell if a selected flag changed */ DrawElement (element); Draw (); SetChangedFlag (true); hid_actionl ("Report", "Object", NULL); } else if (type != NO_TYPE) { TextType *thing = (TextType *) ptr3; TOGGLE_FLAG (LOCKFLAG, thing); if (TEST_FLAG (LOCKFLAG, thing) && TEST_FLAG (SELECTEDFLAG, thing)) { /* this is not un-doable since LOCK isn't */ CLEAR_FLAG (SELECTEDFLAG, thing); DrawObject (type, ptr1, ptr2); Draw (); } SetChangedFlag (true); hid_actionl ("Report", "Object", NULL); } break; } case THERMAL_MODE: { if (((type = SearchScreen (Note.X, Note.Y, PIN_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) && !TEST_FLAG (HOLEFLAG, (PinType *) ptr3)) { if (gui->shift_is_pressed ()) { int tstyle = GET_THERM (INDEXOFCURRENT, (PinType *) ptr3); tstyle++; if (tstyle > 5) tstyle = 1; ChangeObjectThermal (type, ptr1, ptr2, ptr3, tstyle); } else if (GET_THERM (INDEXOFCURRENT, (PinType *) ptr3)) ChangeObjectThermal (type, ptr1, ptr2, ptr3, 0); else ChangeObjectThermal (type, ptr1, ptr2, ptr3, PCB->ThermStyle); } break; } case LINE_MODE: /* do update of position */ NotifyLine (); if (Crosshair.AttachedLine.State != STATE_THIRD) break; /* Remove anchor if clicking on start point; * this means we can't paint 0 length lines * which could be used for square SMD pads. * Instead use a very small delta, or change * the file after saving. */ if (Crosshair.X == Crosshair.AttachedLine.Point1.X && Crosshair.Y == Crosshair.AttachedLine.Point1.Y) { SetMode (LINE_MODE); break; } if (PCB->RatDraw) { RatType *line; if ((line = AddNet ())) { addedLines++; AddObjectToCreateUndoList (RATLINE_TYPE, line, line, line); IncrementUndoSerialNumber (); DrawRat (line); Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; Draw (); } break; } else /* create line if both ends are determined && length != 0 */ { LineType *line; int line_flags = 0; if (TEST_FLAG (AUTODRCFLAG, PCB) && !TEST_SILK_LAYER (CURRENT)) line_flags |= CONNECTEDFLAG | FOUNDFLAG; if (TEST_FLAG (CLEARNEWFLAG, PCB)) line_flags |= CLEARLINEFLAG; if (PCB->Clipping && Crosshair.AttachedLine.Point1.X == Crosshair.AttachedLine.Point2.X && Crosshair.AttachedLine.Point1.Y == Crosshair.AttachedLine.Point2.Y && (Crosshair.AttachedLine.Point2.X != Note.X || Crosshair.AttachedLine.Point2.Y != Note.Y)) { /* We will only need to paint the second line segment. Since we only check for vias on the first segment, swap them so the non-empty segment is the first segment. */ Crosshair.AttachedLine.Point2.X = Note.X; Crosshair.AttachedLine.Point2.Y = Note.Y; } if ((Crosshair.AttachedLine.Point1.X != Crosshair.AttachedLine.Point2.X || Crosshair.AttachedLine.Point1.Y != Crosshair.AttachedLine.Point2.Y)) { PinType *via; Cardinal layer_from, layer_to; if ((line = CreateDrawnLineOnLayer (CURRENT, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, Settings.LineThickness, 2 * Settings.Keepaway, MakeFlags (line_flags))) != NULL) { addedLines++; AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line); DrawLine (CURRENT, line); } /* place a via if vias are visible, the layer is in a new group since the last line and there isn't a pin already here */ if (TEST_FLAG (AUTOBURIEDVIASFLAG, PCB)) { layer_from = GetLayerNumber (PCB->Data, lastLayer); layer_to = GetLayerNumber (PCB->Data, CURRENT); } else { layer_from = 0; layer_to = 0; } if (PCB->ViaOn && GetLayerGroupNumberByPointer (CURRENT) != GetLayerGroupNumberByPointer (lastLayer) && SearchObjectByLocation (PIN_TYPES, &ptr1, &ptr2, &ptr3, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Settings.ViaThickness / 2) == NO_TYPE && (via = CreateNewViaEx (PCB->Data, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, Settings.ViaThickness, 2 * Settings.Keepaway, Settings.ViaMaskAperture, Settings.ViaDrillingHole, NULL, NoFlags (), layer_from, layer_to)) != NULL) { AddObjectToCreateUndoList (VIA_TYPE, via, via, via); DrawVia (via); } /* copy the coordinates */ Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; IncrementUndoSerialNumber (); lastLayer = CURRENT; } if (PCB->Clipping && (Note.X != Crosshair.AttachedLine.Point2.X || Note.Y != Crosshair.AttachedLine.Point2.Y)) { if ((line = CreateDrawnLineOnLayer (CURRENT, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, Note.X, Note.Y, Settings.LineThickness, 2 * Settings.Keepaway, MakeFlags (line_flags))) != NULL) { addedLines++; AddObjectToCreateUndoList (LINE_TYPE, CURRENT, line, line); IncrementUndoSerialNumber (); DrawLine (CURRENT, line); } /* move to new start point */ Crosshair.AttachedLine.Point1.X = Note.X; Crosshair.AttachedLine.Point1.Y = Note.Y; Crosshair.AttachedLine.Point2.X = Note.X; Crosshair.AttachedLine.Point2.Y = Note.Y; if (TEST_FLAG (SWAPSTARTDIRFLAG, PCB)) { PCB->Clipping ^= 3; } } if (TEST_FLAG (AUTODRCFLAG, PCB) && !TEST_SILK_LAYER (CURRENT)) LookupConnection (Note.X, Note.Y, true, 1, CONNECTEDFLAG, false); Draw (); } break; case RECTANGLE_MODE: /* do update of position */ NotifyBlock (); /* create rectangle if both corners are determined * and width, height are != 0 */ if (Crosshair.AttachedBox.State == STATE_THIRD && Crosshair.AttachedBox.Point1.X != Crosshair.AttachedBox.Point2.X && Crosshair.AttachedBox.Point1.Y != Crosshair.AttachedBox.Point2.Y) { PolygonType *polygon; int flags = CLEARPOLYFLAG; if (TEST_FLAG (NEWFULLPOLYFLAG, PCB)) flags |= FULLPOLYFLAG; if ((polygon = CreateNewPolygonFromRectangle (CURRENT, Crosshair. AttachedBox.Point1.X, Crosshair. AttachedBox.Point1.Y, Crosshair. AttachedBox.Point2.X, Crosshair. AttachedBox.Point2.Y, MakeFlags (flags))) != NULL) { AddObjectToCreateUndoList (POLYGON_TYPE, CURRENT, polygon, polygon); IncrementUndoSerialNumber (); DrawPolygon (CURRENT, polygon); Draw (); } /* reset state to 'first corner' */ Crosshair.AttachedBox.State = STATE_FIRST; } break; case TEXT_MODE: { char *string; if ((string = gui->prompt_for (_("Enter text:"), "")) != NULL) { if (strlen(string) > 0) { TextType *text; int flag = CLEARLINEFLAG; if (GetLayerGroupNumberByNumber (INDEXOFCURRENT) == GetLayerGroupNumberBySide (BOTTOM_SIDE)) flag |= ONSOLDERFLAG; if ((text = CreateNewText (CURRENT, &PCB->Font, Note.X, Note.Y, 0, Settings.TextScale, string, MakeFlags (flag))) != NULL) { AddObjectToCreateUndoList (TEXT_TYPE, CURRENT, text, text); IncrementUndoSerialNumber (); DrawText (CURRENT, text); Draw (); } } free (string); } break; } case POLYGON_MODE: { PointType *points = Crosshair.AttachedPolygon.Points; Cardinal n = Crosshair.AttachedPolygon.PointN; /* do update of position; use the 'LINE_MODE' mechanism */ NotifyLine (); /* check if this is the last point of a polygon */ if (n >= 3 && points->X == Crosshair.AttachedLine.Point2.X && points->Y == Crosshair.AttachedLine.Point2.Y) { CopyAttachedPolygonToLayer (); Draw (); break; } /* create new point if it's the first one or if it's * different to the last one */ if (!n || points[n - 1].X != Crosshair.AttachedLine.Point2.X || points[n - 1].Y != Crosshair.AttachedLine.Point2.Y) { CreateNewPointInPolygon (&Crosshair.AttachedPolygon, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y); /* copy the coordinates */ Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; } break; } case POLYGONHOLE_MODE: { switch (Crosshair.AttachedObject.State) { /* first notify, lookup object */ case STATE_FIRST: Crosshair.AttachedObject.Type = SearchScreen (Note.X, Note.Y, POLYGON_TYPE, &Crosshair.AttachedObject.Ptr1, &Crosshair.AttachedObject.Ptr2, &Crosshair.AttachedObject.Ptr3); if (Crosshair.AttachedObject.Type == NO_TYPE) { Message (_("The first point of a polygon hole must be on a polygon.\n")); break; /* don't start doing anything if clicked outside of polys */ } if (TEST_FLAG(LOCKFLAG, (PolygonType *) Crosshair.AttachedObject.Ptr2)) { Message (_("Sorry, the object is locked\n")); Crosshair.AttachedObject.Type = NO_TYPE; break; } else Crosshair.AttachedObject.State = STATE_SECOND; /* Fall thru: first click is also the first point of the * poly hole. */ /* second notify, insert new point into object */ case STATE_SECOND: { PointType *points = Crosshair.AttachedPolygon.Points; Cardinal n = Crosshair.AttachedPolygon.PointN; POLYAREA *original, *new_hole, *result; FlagType Flags; /* do update of position; use the 'LINE_MODE' mechanism */ NotifyLine (); /* check if this is the last point of a polygon */ if (n >= 3 && points->X == Crosshair.AttachedLine.Point2.X && points->Y == Crosshair.AttachedLine.Point2.Y) { /* Create POLYAREAs from the original polygon * and the new hole polygon */ original = PolygonToPoly ((PolygonType *)Crosshair.AttachedObject.Ptr2); new_hole = PolygonToPoly (&Crosshair.AttachedPolygon); /* Subtract the hole from the original polygon shape */ poly_Boolean_free (original, new_hole, &result, PBO_SUB); /* Convert the resulting polygon(s) into a new set of nodes * and place them on the page. Delete the original polygon. */ SaveUndoSerialNumber (); Flags = ((PolygonType *)Crosshair.AttachedObject.Ptr2)->Flags; PolyToPolygonsOnLayer (PCB->Data, (LayerType *)Crosshair.AttachedObject.Ptr1, result, Flags); RemoveObject (POLYGON_TYPE, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, Crosshair.AttachedObject.Ptr3); RestoreUndoSerialNumber (); IncrementUndoSerialNumber (); Draw (); /* reset state of attached line */ memset (&Crosshair.AttachedPolygon, 0, sizeof (PolygonType)); Crosshair.AttachedObject.State = STATE_FIRST; addedLines = 0; break; } /* create new point if it's the first one or if it's * different to the last one */ if (!n || points[n - 1].X != Crosshair.AttachedLine.Point2.X || points[n - 1].Y != Crosshair.AttachedLine.Point2.Y) { CreateNewPointInPolygon (&Crosshair.AttachedPolygon, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y); /* copy the coordinates */ Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; } break; } } break; } case PASTEBUFFER_MODE: { TextType estr[MAX_ELEMENTNAMES]; ElementType *e = 0; if (gui->shift_is_pressed ()) { int type = SearchScreen (Note.X, Note.Y, ELEMENT_TYPE, &ptr1, &ptr2, &ptr3); if (type == ELEMENT_TYPE) { e = (ElementType *) ptr1; if (e) { int i; memcpy (estr, e->Name, MAX_ELEMENTNAMES * sizeof (TextType)); for (i = 0; i < MAX_ELEMENTNAMES; ++i) estr[i].TextString = estr[i].TextString ? strdup(estr[i].TextString) : NULL; RemoveElement (e); } } } if (CopyPastebufferToLayout (Note.X, Note.Y)) SetChangedFlag (true); if (e) { int type = SearchScreen (Note.X, Note.Y, ELEMENT_TYPE, &ptr1, &ptr2, &ptr3); if (type == ELEMENT_TYPE && ptr1) { int i, save_n; e = (ElementType *) ptr1; save_n = NAME_INDEX (PCB); for (i = 0; i < MAX_ELEMENTNAMES; i++) { if (i == save_n) EraseElementName (e); r_delete_entry (PCB->Data->name_tree[i], (BoxType *) & (e->Name[i])); memcpy (&(e->Name[i]), &(estr[i]), sizeof (TextType)); e->Name[i].Element = e; SetTextBoundingBox (&PCB->Font, &(e->Name[i])); r_insert_entry (PCB->Data->name_tree[i], (BoxType *) & (e->Name[i]), 0); if (i == save_n) DrawElementName (e); } } } break; } case REMOVE_MODE: if ((type = SearchScreen (Note.X, Note.Y, REMOVE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) { if (TEST_FLAG (LOCKFLAG, (LineType *) ptr2)) { Message (_("Sorry, the object is locked\n")); break; } if (type == ELEMENT_TYPE) { RubberbandType *ptr; int i; Crosshair.AttachedObject.RubberbandN = 0; LookupRatLines (type, ptr1, ptr2, ptr3); ptr = Crosshair.AttachedObject.Rubberband; for (i = 0; i < Crosshair.AttachedObject.RubberbandN; i++) { if (PCB->RatOn) EraseRat ((RatType *) ptr->Line); if (TEST_FLAG (RUBBERENDFLAG, ptr->Line)) MoveObjectToRemoveUndoList (RATLINE_TYPE, ptr->Line, ptr->Line, ptr->Line); else TOGGLE_FLAG (RUBBERENDFLAG, ptr->Line); /* only remove line once */ ptr++; } } RemoveObject (type, ptr1, ptr2, ptr3); IncrementUndoSerialNumber (); SetChangedFlag (true); } break; case ROTATE_MODE: RotateScreenObject (Note.X, Note.Y, gui->shift_is_pressed ()? (SWAP_IDENT ? 1 : 3) : (SWAP_IDENT ? 3 : 1)); break; /* both are almost the same */ case COPY_MODE: case MOVE_MODE: switch (Crosshair.AttachedObject.State) { /* first notify, lookup object */ case STATE_FIRST: { int types = (Settings.Mode == COPY_MODE) ? COPY_TYPES : MOVE_TYPES; Crosshair.AttachedObject.Type = SearchScreen (Note.X, Note.Y, types, &Crosshair.AttachedObject.Ptr1, &Crosshair.AttachedObject.Ptr2, &Crosshair.AttachedObject.Ptr3); if (Crosshair.AttachedObject.Type != NO_TYPE) { if (Settings.Mode == MOVE_MODE && TEST_FLAG (LOCKFLAG, (PinType *) Crosshair.AttachedObject.Ptr2)) { Message (_("Sorry, the object is locked\n")); Crosshair.AttachedObject.Type = NO_TYPE; } else AttachForCopy (Note.X, Note.Y); } break; } /* second notify, move or copy object */ case STATE_SECOND: if (Settings.Mode == COPY_MODE) CopyObject (Crosshair.AttachedObject.Type, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, Crosshair.AttachedObject.Ptr3, Note.X - Crosshair.AttachedObject.X, Note.Y - Crosshair.AttachedObject.Y); else { MoveObjectAndRubberband (Crosshair.AttachedObject.Type, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, Crosshair.AttachedObject.Ptr3, Note.X - Crosshair.AttachedObject.X, Note.Y - Crosshair.AttachedObject.Y); SetLocalRef (0, 0, false); } SetChangedFlag (true); /* reset identifiers */ Crosshair.AttachedObject.Type = NO_TYPE; Crosshair.AttachedObject.State = STATE_FIRST; break; } break; /* insert a point into a polygon/line/... */ case INSERTPOINT_MODE: switch (Crosshair.AttachedObject.State) { /* first notify, lookup object */ case STATE_FIRST: Crosshair.AttachedObject.Type = SearchScreen (Note.X, Note.Y, INSERT_TYPES, &Crosshair.AttachedObject.Ptr1, &Crosshair.AttachedObject.Ptr2, &Crosshair.AttachedObject.Ptr3); if (Crosshair.AttachedObject.Type != NO_TYPE) { if (TEST_FLAG (LOCKFLAG, (PolygonType *) Crosshair.AttachedObject.Ptr2)) { Message (_("Sorry, the object is locked\n")); Crosshair.AttachedObject.Type = NO_TYPE; break; } else { /* get starting point of nearest segment */ if (Crosshair.AttachedObject.Type == POLYGON_TYPE) { fake.poly = (PolygonType *) Crosshair.AttachedObject.Ptr2; polyIndex = GetLowestDistancePolygonPoint (fake.poly, Note.X, Note.Y); fake.line.Point1 = fake.poly->Points[polyIndex]; fake.line.Point2 = fake.poly->Points[ prev_contour_point (fake.poly, polyIndex)]; Crosshair.AttachedObject.Ptr2 = &fake.line; } Crosshair.AttachedObject.State = STATE_SECOND; InsertedPoint = *AdjustInsertPoint (); } } break; /* second notify, insert new point into object */ case STATE_SECOND: if (Crosshair.AttachedObject.Type == POLYGON_TYPE) InsertPointIntoObject (POLYGON_TYPE, Crosshair.AttachedObject.Ptr1, fake.poly, &polyIndex, InsertedPoint.X, InsertedPoint.Y, false, false); else InsertPointIntoObject (Crosshair.AttachedObject.Type, Crosshair.AttachedObject.Ptr1, Crosshair.AttachedObject.Ptr2, &polyIndex, InsertedPoint.X, InsertedPoint.Y, false, false); SetChangedFlag (true); /* reset identifiers */ Crosshair.AttachedObject.Type = NO_TYPE; Crosshair.AttachedObject.State = STATE_FIRST; break; } break; } } /* --------------------------------------------------------------------------- */ static const char atomic_syntax[] = N_("Atomic(Save|Restore|Close|Block)"); static const char atomic_help[] = N_("Save or restore the undo serial number."); /* %start-doc actions Atomic This action allows making multiple-action bindings into an atomic operation that will be undone by a single Undo command. For example, to optimize rat lines, you'd delete the rats and re-add them. To group these into a single undo, you'd want the deletions and the additions to have the same undo serial number. So, you @code{Save}, delete the rats, @code{Restore}, add the rats - using the same serial number as the deletes, then @code{Block}, which checks to see if the deletions or additions actually did anything. If not, the serial number is set to the saved number, as there's nothing to undo. If something did happen, the serial number is incremented so that these actions are counted as a single undo step. @table @code @item Save Saves the undo serial number. @item Restore Returns it to the last saved number. @item Close Sets it to 1 greater than the last save. @item Block Does a Restore if there was nothing to undo, else does a Close. @end table %end-doc */ static int ActionAtomic (int argc, char **argv, Coord x, Coord y) { if (argc != 1) AFAIL (atomic); switch (GetFunctionID (argv[0])) { case F_Save: SaveUndoSerialNumber (); break; case F_Restore: RestoreUndoSerialNumber (); break; case F_Close: RestoreUndoSerialNumber (); IncrementUndoSerialNumber (); break; case F_Block: RestoreUndoSerialNumber (); if (Bumped) IncrementUndoSerialNumber (); break; } return 0; } /* -------------------------------------------------------------------------- */ static const char dumplibrary_syntax[] = N_("DumpLibrary()"); static const char dumplibrary_help[] = N_("Display the entire contents of the libraries."); /* %start-doc actions DumpLibrary %end-doc */ static int ActionDumpLibrary (int argc, char **argv, Coord x, Coord y) { int i, j; printf ("**** Do not count on this format. It will change ****\n\n"); printf ("MenuN = %d\n", (int) Library.MenuN); printf ("MenuMax = %d\n", (int) Library.MenuMax); for (i = 0; i < Library.MenuN; i++) { printf ("Library #%d:\n", i); printf (" EntryN = %d\n", (int) Library.Menu[i].EntryN); printf (" EntryMax = %d\n", (int) Library.Menu[i].EntryMax); printf (" Name = \"%s\"\n", UNKNOWN (Library.Menu[i].Name)); printf (" directory = \"%s\"\n", UNKNOWN (Library.Menu[i].directory)); printf (" Style = \"%s\"\n", UNKNOWN (Library.Menu[i].Style)); printf (" flag = %d\n", Library.Menu[i].flag); for (j = 0; j < Library.Menu[i].EntryN; j++) { printf (" #%4d: ", j); if (Library.Menu[i].Entry[j].Template == (char *) -1) { printf ("newlib: \"%s\"\n", UNKNOWN (Library.Menu[i].Entry[j].ListEntry)); } else { printf ("\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"\n", UNKNOWN (Library.Menu[i].Entry[j].ListEntry), UNKNOWN (Library.Menu[i].Entry[j].Template), UNKNOWN (Library.Menu[i].Entry[j].Package), UNKNOWN (Library.Menu[i].Entry[j].Value), UNKNOWN (Library.Menu[i].Entry[j].Description)); } } } return 0; } /* -------------------------------------------------------------------------- */ static const char flip_syntax[] = N_("Flip(Object|Selected|SelectedElements)"); static const char flip_help[] = N_("Flip an element to the opposite side of the board."); /* %start-doc actions Flip Note that the location of the element will be symmetric about the cursor location; i.e. if the part you are pointing at will still be at the same spot once the element is on the other side. When flipping multiple elements, this retains their positions relative to each other, not their absolute positions on the board. %end-doc */ static int ActionFlip (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); ElementType *element; void *ptrtmp; int err = 0; if (function) { switch (GetFunctionID (function)) { case F_Object: if ((SearchScreen (x, y, ELEMENT_TYPE, &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE) { element = (ElementType *) ptrtmp; ChangeElementSide (element, 2 * Crosshair.Y - PCB->MaxHeight); IncrementUndoSerialNumber (); Draw (); } break; case F_Selected: case F_SelectedElements: ChangeSelectedElementSide (); break; default: err = 1; break; } if (!err) return 0; } AFAIL (flip); } /* -------------------------------------------------------------------------- */ static const char message_syntax[] = N_("Message(message)"); static const char message_help[] = N_("Writes a message to the log window."); /* %start-doc actions Message This action displays a message to the log window. This action is primarily provided for use by other programs which may interface with PCB. If multiple arguments are given, each one is sent to the log window followed by a newline. %end-doc */ static int ActionMessage (int argc, char **argv, Coord x, Coord y) { int i; if (argc < 1) AFAIL (message); for (i = 0; i < argc; i++) { Message (argv[i]); Message ("\n"); } return 0; } /* -------------------------------------------------------------------------- */ static const char setthermal_syntax[] = "SetThermal(Object|SelectedPins|SelectedVias|Selected, Style)"; static const char setthermal_help[] = N_("Set the thermal (on the current layer) of pins or vias to the given style.\n" "Style = 0 means no thermal.\n" "Style = 1 has diagonal fingers with sharp edges.\n" "Style = 2 has horizontal and vertical fingers with sharp edges.\n" "Style = 3 is a solid connection to the plane.\n" "Style = 4 has diagonal fingers with rounded edges.\n" "Style = 5 has horizontal and vertical fingers with rounded edges.\n"); /* %start-doc actions SetThermal This changes how/whether pins or vias connect to any rectangle or polygon on the current layer. The first argument can specify one object, or all selected pins, or all selected vias, or all selected pins and vias. The second argument specifies the style of connection. There are 5 possibilities: 0 - no connection, 1 - 45 degree fingers with sharp edges, 2 - horizontal & vertical fingers with sharp edges, 3 - solid connection, 4 - 45 degree fingers with rounded corners, 5 - horizontal & vertical fingers with rounded corners. Pins and Vias may have thermals whether or not there is a polygon available to connect with. However, they will have no effect without the polygon. %end-doc */ static int ActionSetThermal (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *style = ARG (1); void *ptr1, *ptr2, *ptr3; int type, kind; int err = 0; if (function && *function) { bool absolute; if ( ! style || ! *style) { kind = PCB->ThermStyle; absolute = true; } else kind = GetUnitlessValue (style, &absolute); /* To allow relative values we could search for the first selected item and make 'kind' relative to that, but that's not too useful and requires quite some code. For example there's no GetFirstSelectedPin() function available. Let's postpone this functionality, there are more urgent things to do. */ if (absolute) switch (GetFunctionID (function)) { case F_Object: if ((type = SearchScreen (Crosshair.X, Crosshair.Y, CHANGETHERMAL_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) { ChangeObjectThermal (type, ptr1, ptr2, ptr3, kind); IncrementUndoSerialNumber (); Draw (); } break; case F_SelectedPins: ChangeSelectedThermals (PIN_TYPE, kind); break; case F_SelectedVias: ChangeSelectedThermals (VIA_TYPE, kind); break; case F_Selected: case F_SelectedElements: ChangeSelectedThermals (CHANGETHERMAL_TYPES, kind); break; default: err = 1; break; } else err = 1; } else err = 1; if (err) AFAIL (setthermal); return 0; } /*! * \brief Event handler to set the cursor according to the X pointer * position called from inside main.c. * * \warning !!! no action routine !!! */ void EventMoveCrosshair (int ev_x, int ev_y) { #ifdef HAVE_LIBSTROKE if (mid_stroke) { StrokeBox.X2 = ev_x; StrokeBox.Y2 = ev_y; stroke_record (ev_x, ev_y); return; } #endif /* HAVE_LIBSTROKE */ if (MoveCrosshairAbsolute (ev_x, ev_y)) { /* update object position and cursor location */ AdjustAttachedObjects (); notify_crosshair_change (true); } } /* --------------------------------------------------------------------------- */ static const char setvalue_syntax[] = N_("SetValue(Grid|Line|LineSize|Text|TextScale|ViaDrillingHole|Via|ViaSize, " "delta)"); static const char setvalue_help[] = N_("Change various board-wide values and sizes."); /* %start-doc actions SetValue @table @code @item ViaDrillingHole Changes the diameter of the drill for new vias. @item Grid Sets the grid spacing. @item Line @item LineSize Changes the thickness of new lines. @item Via @item ViaSize Changes the diameter of new vias. @item Text @item TextScale Changes the size of new text. @end table %end-doc */ static int ActionSetValue (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *val = ARG (1); char *units = ARG (2); bool absolute; /* flag for 'absolute' value */ double value; int text_scale; int err = 0; if (function && val) { value = GetValue (val, units, &absolute); switch (GetFunctionID (function)) { case F_ViaDrillingHole: SetViaDrillingHole (absolute ? value : value + Settings.ViaDrillingHole, false); hid_action ("RouteStylesChanged"); break; case F_Grid: if (absolute) SetGrid (value, false); else { if (value == 0) value = val[0] == '-' ? -Settings.increments->grid : Settings.increments->grid; /* On the way down, short against the minimum * PCB drawing unit */ if ((value + PCB->Grid) < 1) SetGrid (1, false); else if (PCB->Grid == 1) SetGrid (value, false); else SetGrid (value + PCB->Grid, false); } break; case F_LineSize: case F_Line: if (!absolute && value == 0) value = val[0] == '-' ? -Settings.increments->line : Settings.increments->line; SetLineSize (absolute ? value : value + Settings.LineThickness); hid_action ("RouteStylesChanged"); break; case F_Via: case F_ViaSize: SetViaSize (absolute ? value : value + Settings.ViaThickness, false); hid_action ("RouteStylesChanged"); break; case F_Text: case F_TextScale: text_scale = value / (double)FONT_CAPHEIGHT * 100.; if (!absolute) text_scale += Settings.TextScale; SetTextScale (text_scale); break; default: err = 1; break; } if (!err) return 0; } AFAIL (setvalue); } /* --------------------------------------------------------------------------- */ static const char quit_syntax[] = N_("Quit()"); static const char quit_help[] = N_("Quits the application after confirming."); /* %start-doc actions Quit If you have unsaved changes, you will be prompted to confirm (or save) before quitting. %end-doc */ static int ActionQuit (int argc, char **argv, Coord x, Coord y) { char *force = ARG (0); if (force && strcasecmp (force, "force") == 0) { PCB->Changed = 0; exit (0); } if (!PCB->Changed || gui->close_confirm_dialog () == HID_CLOSE_CONFIRM_OK) QuitApplication (); return 1; } /* --------------------------------------------------------------------------- */ static const char connection_syntax[] = N_("Connection(Find|ResetLinesAndPolygons|ResetPinsAndVias|Reset)"); static const char connection_help[] = N_("Searches connections of the object at the cursor position."); /* %start-doc actions Connection Connections found with this action will be highlighted in the ``connected-color'' color and will have the ``found'' flag set. @table @code @item Find The net under the cursor is ``found''. @item ResetLinesAndPolygons Any ``found'' lines and polygons are marked ``not found''. @item ResetPinsAndVias Any ``found'' pins and vias are marked ``not found''. @item Reset All ``found'' objects are marked ``not found''. @end table %end-doc */ static int ActionConnection (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_Find: { gui->get_coords (_("Click on a connection"), &x, &y); LookupConnection (x, y, true, 1, CONNECTEDFLAG, false); LookupConnection (x, y, true, 1, FOUNDFLAG, true); break; } case F_ResetLinesAndPolygons: if (ClearFlagOnLinesAndPolygons (CONNECTEDFLAG | FOUNDFLAG, true)) { IncrementUndoSerialNumber (); Draw (); } break; case F_ResetPinsViasAndPads: if (ClearFlagOnPinsViasAndPads (CONNECTEDFLAG | FOUNDFLAG, true)) { IncrementUndoSerialNumber (); Draw (); } break; case F_Reset: if (ClearFlagOnAllObjects (CONNECTEDFLAG | FOUNDFLAG, true)) { IncrementUndoSerialNumber (); Draw (); } break; } return 0; } AFAIL (connection); } /* --------------------------------------------------------------------------- */ static const char disperseelements_syntax[] = N_("DisperseElements(All|Selected)"); static const char disperseelements_help[] = N_("Disperses elements."); /* %start-doc actions DisperseElements Normally this is used when starting a board, by selecting all elements and then dispersing them. This scatters the elements around the board so that you can pick individual ones, rather than have all the elements at the same 0,0 coordinate and thus impossible to choose from. %end-doc */ #define GAP MIL_TO_COORD(100) static int ActionDisperseElements (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); Coord minx = GAP, miny = GAP, maxy = GAP, dx, dy; int all = 0, bad = 0; if (!function || !*function) { bad = 1; } else { switch (GetFunctionID (function)) { case F_All: all = 1; break; case F_Selected: all = 0; break; default: bad = 1; } } if (bad) { AFAIL (disperseelements); } ELEMENT_LOOP (PCB->Data); { /* * If we want to disperse selected elements, maybe we need smarter * code here to avoid putting components on top of others which * are not selected. For now, I'm assuming that this is typically * going to be used either with a brand new design or a scratch * design holding some new components */ if (!TEST_FLAG (LOCKFLAG, element) && (all || TEST_FLAG (SELECTEDFLAG, element))) { /* figure out how much to move the element */ dx = minx - element->BoundingBox.X1; /* snap to the grid */ dx -= (element->MarkX + dx) % PCB->Grid; /* * and add one grid size so we make sure we always space by GAP or * more */ dx += PCB->Grid; /* Figure out if this row has room. If not, start a new row */ if (GAP + element->BoundingBox.X2 + dx > PCB->MaxWidth) { miny = maxy + GAP; minx = GAP; } /* figure out how much to move the element */ dx = minx - element->BoundingBox.X1; dy = miny - element->BoundingBox.Y1; /* snap to the grid */ dx -= (element->MarkX + dx) % PCB->Grid; dx += PCB->Grid; dy -= (element->MarkY + dy) % PCB->Grid; dy += PCB->Grid; /* move the element */ MoveElementLowLevel (PCB->Data, element, dx, dy); /* and add to the undo list so we can undo this operation */ AddObjectToMoveUndoList (ELEMENT_TYPE, NULL, NULL, element, dx, dy); /* keep track of how tall this row is */ minx += element->BoundingBox.X2 - element->BoundingBox.X1 + GAP; if (maxy < element->BoundingBox.Y2) { maxy = element->BoundingBox.Y2; } } } END_LOOP; /* done with our action so increment the undo # */ IncrementUndoSerialNumber (); Redraw (); SetChangedFlag (true); return 0; } #undef GAP /* --------------------------------------------------------------------------- */ static const char display_syntax[] = N_("Display(NameOnPCB|Description|Value)\n" "Display(Grid|Redraw)\n" "Display(CycleClip|CycleCrosshair|Toggle45Degree|ToggleStartDirection)\n" "Display(ToggleGrid|ToggleRubberBandMode|ToggleUniqueNames)\n" "Display(ToggleMask|ToggleName|ToggleClearLine|ToggleFullPoly|ToggleSnapPin)\n" "Display(ToggleThindraw|ToggleThindrawPoly|ToggleOrthoMove|ToggleLocalRef)\n" "Display(ToggleCheckPlanes|ToggleShowDRC|ToggleAutoDRC)\n" "Display(ToggleLiveRoute|LockNames|OnlyNames)\n" "Display(Pinout|PinOrPadName)"); static const char display_help[] = N_("Several display-related actions."); /* %start-doc actions Display @table @code @item NameOnPCB @item Description @item Value Specify whether all elements show their name, description, or value. @item Redraw Redraw the whole board. @item Toggle45Degree When clear, lines can be drawn at any angle. When set, lines are restricted to multiples of 45 degrees and requested lines may be broken up according to the clip setting. @item CycleClip Changes the way lines are restricted to 45 degree increments. The various settings are: straight only, orthogonal then angled, and angled then orthogonal. If AllDirections is set, this action disables it. @item CycleCrosshair Changes crosshair drawing. Crosshair may accept form of 4-ray, 8-ray and 12-ray cross. @item ToggleRubberBandMode If set, moving an object moves all the lines attached to it too. @item ToggleStartDirection If set, each time you set a point in a line, the Clip toggles between orth-angle and angle-ortho. @item ToggleUniqueNames If set, you will not be permitted to change the name of an element to match that of another element. @item ToggleSnapPin If set, pin centers and pad end points are treated as additional grid points that the cursor can snap to. @item ToggleLocalRef If set, the mark is automatically set to the beginning of any move, so you can see the relative distance you've moved. @item ToggleThindraw If set, objects on the screen are drawn as outlines (lines are drawn as center-lines). This lets you see line endpoints hidden under pins, for example. @item ToggleThindrawPoly If set, polygons on the screen are drawn as outlines. @item ToggleShowDRC If set, pending objects (i.e. lines you're in the process of drawing) will be drawn with an outline showing how far away from other copper you need to be. @item ToggleLiveRoute If set, the progress of the autorouter will be visible on the screen. @item ToggleAutoDRC If set, you will not be permitted to make connections which violate the current DRC and netlist settings. @item ToggleCheckPlanes If set, lines and arcs aren't drawn, which usually leaves just the polygons. If you also disable all but the layer you're interested in, this allows you to check for isolated regions. @item ToggleOrthoMove If set, the crosshair is only allowed to move orthogonally from its previous position. I.e. you can move an element or line up, down, left, or right, but not up+left or down+right. @item ToggleName Selects whether the pinouts show the pin names or the pin numbers. @item ToggleLockNames If set, text will ignore left mouse clicks and actions that work on objects under the mouse. You can still select text with a lasso (left mouse drag) and perform actions on the selection. @item ToggleOnlyNames If set, only text will be sensitive for mouse clicks and actions that work on objects under the mouse. You can still select other objects with a lasso (left mouse drag) and perform actions on the selection. @item ToggleMask Turns the solder mask on or off. @item ToggleClearLine When set, the clear-line flag causes new lines and arcs to have their ``clear polygons'' flag set, so they won't be electrically connected to any polygons they overlap. @item ToggleFullPoly When set, the full-poly flag causes new polygons to have their ``full polygon'' flag set, so all parts of them will be displayed instead of only the biggest one. @item ToggleGrid Resets the origin of the current grid to be wherever the mouse pointer is (not where the crosshair currently is). If you provide two numbers after this, the origin is set to that coordinate. @item Grid Toggles whether the grid is displayed or not. @item Pinout Causes the pinout of the element indicated by the cursor to be displayed, usually in a separate window. @item PinOrPadName Toggles whether the names of pins, pads, or (yes) vias will be displayed. If the cursor is over an element, all of its pins and pads are affected. @item ToggleAutoBuriedVias If set, automatically created vias are buried vias. @end table %end-doc */ static enum crosshair_shape CrosshairShapeIncrement (enum crosshair_shape shape) { switch(shape) { case Basic_Crosshair_Shape: shape = Union_Jack_Crosshair_Shape; break; case Union_Jack_Crosshair_Shape: shape = Dozen_Crosshair_Shape; break; case Dozen_Crosshair_Shape: shape = Crosshair_Shapes_Number; break; case Crosshair_Shapes_Number: shape = Basic_Crosshair_Shape; break; } return shape; } static int ActionDisplay (int argc, char **argv, Coord childX, Coord childY) { char *function, *str_dir; int id; int err = 0; function = ARG (0); str_dir = ARG (1); if (function && (!str_dir || !*str_dir)) { switch (id = GetFunctionID (function)) { /* redraw layout */ case F_ClearAndRedraw: case F_Redraw: Redraw (); break; /* change the displayed name of elements */ case F_Value: case F_NameOnPCB: case F_Description: ELEMENT_LOOP (PCB->Data); { EraseElementName (element); } END_LOOP; CLEAR_FLAG (DESCRIPTIONFLAG | NAMEONPCBFLAG, PCB); switch (id) { case F_Value: break; case F_NameOnPCB: SET_FLAG (NAMEONPCBFLAG, PCB); break; case F_Description: SET_FLAG (DESCRIPTIONFLAG, PCB); break; } ELEMENT_LOOP (PCB->Data); { DrawElementName (element); } END_LOOP; Draw (); break; /* toggle line-adjust flag */ case F_ToggleAllDirections: TOGGLE_FLAG (ALLDIRECTIONFLAG, PCB); AdjustAttachedObjects (); break; case F_CycleClip: notify_crosshair_change (false); if (TEST_FLAG (ALLDIRECTIONFLAG, PCB)) { TOGGLE_FLAG (ALLDIRECTIONFLAG, PCB); PCB->Clipping = 0; } else PCB->Clipping = (PCB->Clipping + 1) % 3; AdjustAttachedObjects (); notify_crosshair_change (true); break; case F_CycleCrosshair: notify_crosshair_change (false); Crosshair.shape = CrosshairShapeIncrement(Crosshair.shape); if (Crosshair_Shapes_Number == Crosshair.shape) Crosshair.shape = Basic_Crosshair_Shape; notify_crosshair_change (true); break; case F_ToggleRubberBandMode: notify_crosshair_change (false); TOGGLE_FLAG (RUBBERBANDFLAG, PCB); notify_crosshair_change (true); break; case F_ToggleAutoBuriedVias: notify_crosshair_change (false); TOGGLE_FLAG (AUTOBURIEDVIASFLAG, PCB); notify_crosshair_change (true); break; case F_ToggleStartDirection: notify_crosshair_change (false); TOGGLE_FLAG (SWAPSTARTDIRFLAG, PCB); notify_crosshair_change (true); break; case F_ToggleUniqueNames: TOGGLE_FLAG (UNIQUENAMEFLAG, PCB); break; case F_ToggleSnapPin: notify_crosshair_change (false); TOGGLE_FLAG (SNAPPINFLAG, PCB); notify_crosshair_change (true); break; case F_ToggleLocalRef: TOGGLE_FLAG (LOCALREFFLAG, PCB); break; case F_ToggleThindraw: TOGGLE_FLAG (THINDRAWFLAG, PCB); Redraw (); break; case F_ToggleThindrawPoly: TOGGLE_FLAG (THINDRAWPOLYFLAG, PCB); Redraw (); break; case F_ToggleLockNames: TOGGLE_FLAG (LOCKNAMESFLAG, PCB); CLEAR_FLAG (ONLYNAMESFLAG, PCB); break; case F_ToggleOnlyNames: TOGGLE_FLAG (ONLYNAMESFLAG, PCB); CLEAR_FLAG (LOCKNAMESFLAG, PCB); break; case F_ToggleHideNames: TOGGLE_FLAG (HIDENAMESFLAG, PCB); Redraw (); break; case F_ToggleShowDRC: TOGGLE_FLAG (SHOWDRCFLAG, PCB); break; case F_ToggleLiveRoute: TOGGLE_FLAG (LIVEROUTEFLAG, PCB); break; case F_ToggleAutoDRC: notify_crosshair_change (false); TOGGLE_FLAG (AUTODRCFLAG, PCB); if (TEST_FLAG (AUTODRCFLAG, PCB) && Settings.Mode == LINE_MODE) { if (ClearFlagOnAllObjects (CONNECTEDFLAG | FOUNDFLAG, true)) { IncrementUndoSerialNumber (); Draw (); } if (Crosshair.AttachedLine.State != STATE_FIRST) { LookupConnection (Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, true, 1, CONNECTEDFLAG, false); LookupConnection (Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, true, 1, FOUNDFLAG, true); } } notify_crosshair_change (true); break; case F_ToggleCheckPlanes: TOGGLE_FLAG (CHECKPLANESFLAG, PCB); Redraw (); break; case F_ToggleOrthoMove: TOGGLE_FLAG (ORTHOMOVEFLAG, PCB); break; case F_ToggleName: TOGGLE_FLAG (SHOWNUMBERFLAG, PCB); Redraw (); break; case F_ToggleMask: TOGGLE_FLAG (SHOWMASKFLAG, PCB); Redraw (); break; case F_ToggleClearLine: TOGGLE_FLAG (CLEARNEWFLAG, PCB); break; case F_ToggleFullPoly: TOGGLE_FLAG (NEWFULLPOLYFLAG, PCB); break; /* shift grid alignment */ case F_ToggleGrid: { Coord oldGrid = PCB->Grid; PCB->Grid = 1; if (MoveCrosshairAbsolute (Crosshair.X, Crosshair.Y)) notify_crosshair_change (true); /* first notify was in MoveCrosshairAbs */ SetGrid (oldGrid, true); } break; /* toggle displaying of the grid */ case F_Grid: Settings.DrawGrid = !Settings.DrawGrid; Redraw (); break; /* display the pinout of an element */ case F_Pinout: { ElementType *element; void *ptrtmp; Coord x, y; gui->get_coords (_("Click on an element"), &x, &y); if ((SearchScreen (x, y, ELEMENT_TYPE, &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE) { element = (ElementType *) ptrtmp; gui->show_item (element); } break; } /* toggle displaying of pin/pad/via names */ case F_PinOrPadName: { void *ptr1, *ptr2, *ptr3; Coord x, y; gui->get_coords(_("Click on an element"), &x, &y); switch (SearchScreen (x, y, ELEMENT_TYPE | PIN_TYPE | PAD_TYPE | VIA_TYPE, (void **) &ptr1, (void **) &ptr2, (void **) &ptr3)) { case ELEMENT_TYPE: PIN_LOOP ((ElementType *) ptr1); { if (TEST_FLAG (DISPLAYNAMEFLAG, pin)) ErasePinName (pin); else DrawPinName (pin); AddObjectToFlagUndoList (PIN_TYPE, ptr1, pin, pin); TOGGLE_FLAG (DISPLAYNAMEFLAG, pin); } END_LOOP; PAD_LOOP ((ElementType *) ptr1); { if (TEST_FLAG (DISPLAYNAMEFLAG, pad)) ErasePadName (pad); else DrawPadName (pad); AddObjectToFlagUndoList (PAD_TYPE, ptr1, pad, pad); TOGGLE_FLAG (DISPLAYNAMEFLAG, pad); } END_LOOP; SetChangedFlag (true); IncrementUndoSerialNumber (); Draw (); break; case PIN_TYPE: if (TEST_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2)) ErasePinName ((PinType *) ptr2); else DrawPinName ((PinType *) ptr2); AddObjectToFlagUndoList (PIN_TYPE, ptr1, ptr2, ptr3); TOGGLE_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2); SetChangedFlag (true); IncrementUndoSerialNumber (); Draw (); break; case PAD_TYPE: if (TEST_FLAG (DISPLAYNAMEFLAG, (PadType *) ptr2)) ErasePadName ((PadType *) ptr2); else DrawPadName ((PadType *) ptr2); AddObjectToFlagUndoList (PAD_TYPE, ptr1, ptr2, ptr3); TOGGLE_FLAG (DISPLAYNAMEFLAG, (PadType *) ptr2); SetChangedFlag (true); IncrementUndoSerialNumber (); Draw (); break; case VIA_TYPE: if (TEST_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2)) EraseViaName ((PinType *) ptr2); else DrawViaName ((PinType *) ptr2); AddObjectToFlagUndoList (VIA_TYPE, ptr1, ptr2, ptr3); TOGGLE_FLAG (DISPLAYNAMEFLAG, (PinType *) ptr2); SetChangedFlag (true); IncrementUndoSerialNumber (); Draw (); break; } break; } default: err = 1; } } else if (function && str_dir) { switch (GetFunctionID (function)) { case F_ToggleGrid: if (argc > 2) { PCB->GridOffsetX = GetValue (argv[1], NULL, NULL); PCB->GridOffsetY = GetValue (argv[2], NULL, NULL); if (Settings.DrawGrid) Redraw (); } break; default: err = 1; break; } } else err = 1; if (err) AFAIL (display); return 0; } /* --------------------------------------------------------------------------- */ static const char mode_syntax[] = N_("Mode(Arc|Arrow|Copy|InsertPoint|Line|Lock|Move|None|PasteBuffer)\n" "Mode(Polygon|Rectangle|Remove|Rotate|Text|Thermal|Via)\n" "Mode(Notify|Release|Cancel|Stroke)\n" "Mode(Save|Restore)"); static const char mode_help[] = N_("Change or use the tool mode."); /* %start-doc actions Mode @table @code @item Arc @itemx Arrow @itemx Copy @itemx InsertPoint @itemx Line @itemx Lock @itemx Move @itemx None @itemx PasteBuffer @itemx Polygon @itemx Rectangle @itemx Remove @itemx Rotate @itemx Text @itemx Thermal @itemx Via Select the indicated tool. @item Notify Called when you press the mouse button, or move the mouse. @item Release Called when you release the mouse button. @item Cancel Cancels any pending tool activity, allowing you to restart elsewhere. For example, this allows you to start a new line rather than attach a line to the previous line. @item Escape Similar to Cancel but calling this action a second time will return to the Arrow tool. @item Stroke If your @code{pcb} was built with libstroke, this invokes the stroke input method. If not, this will restart a drawing mode if you were drawing, else it will select objects. @item Save Remembers the current tool. @item Restore Restores the tool to the last saved tool. @end table %end-doc */ static int ActionMode (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { Note.X = Crosshair.X; Note.Y = Crosshair.Y; notify_crosshair_change (false); switch (GetFunctionID (function)) { case F_Arc: SetMode (ARC_MODE); break; case F_Arrow: SetMode (ARROW_MODE); break; case F_Copy: SetMode (COPY_MODE); break; case F_InsertPoint: SetMode (INSERTPOINT_MODE); break; case F_Line: SetMode (LINE_MODE); break; case F_Lock: SetMode (LOCK_MODE); break; case F_Move: SetMode (MOVE_MODE); break; case F_None: SetMode (NO_MODE); break; case F_Cancel: { int saved_mode = Settings.Mode; SetMode (NO_MODE); SetMode (saved_mode); } break; case F_Escape: { switch (Settings.Mode) { case VIA_MODE: case PASTEBUFFER_MODE: case TEXT_MODE: case ROTATE_MODE: case REMOVE_MODE: case MOVE_MODE: case COPY_MODE: case INSERTPOINT_MODE: case RUBBERBANDMOVE_MODE: case THERMAL_MODE: case LOCK_MODE: SetMode (NO_MODE); SetMode (ARROW_MODE); break; case LINE_MODE: if (Crosshair.AttachedLine.State == STATE_FIRST) SetMode (ARROW_MODE); else { SetMode (NO_MODE); SetMode (LINE_MODE); } break; case RECTANGLE_MODE: if (Crosshair.AttachedBox.State == STATE_FIRST) SetMode (ARROW_MODE); else { SetMode (NO_MODE); SetMode (RECTANGLE_MODE); } break; case POLYGON_MODE: if (Crosshair.AttachedLine.State == STATE_FIRST) SetMode (ARROW_MODE); else { SetMode (NO_MODE); SetMode (POLYGON_MODE); } break; case POLYGONHOLE_MODE: if (Crosshair.AttachedLine.State == STATE_FIRST) SetMode (ARROW_MODE); else { SetMode (NO_MODE); SetMode (POLYGONHOLE_MODE); } break; case ARC_MODE: if (Crosshair.AttachedBox.State == STATE_FIRST) SetMode (ARROW_MODE); else { SetMode (NO_MODE); SetMode (ARC_MODE); } break; case ARROW_MODE: break; default: break; } } break; case F_Notify: NotifyMode (); break; case F_PasteBuffer: SetMode (PASTEBUFFER_MODE); break; case F_Polygon: SetMode (POLYGON_MODE); break; case F_PolygonHole: SetMode (POLYGONHOLE_MODE); break; #ifndef HAVE_LIBSTROKE case F_Release: ReleaseMode (); break; #else case F_Release: if (mid_stroke) FinishStroke (); else ReleaseMode (); break; #endif case F_Remove: SetMode (REMOVE_MODE); break; case F_Rectangle: SetMode (RECTANGLE_MODE); break; case F_Rotate: SetMode (ROTATE_MODE); break; case F_Stroke: #ifdef HAVE_LIBSTROKE mid_stroke = true; StrokeBox.X1 = Crosshair.X; StrokeBox.Y1 = Crosshair.Y; break; #else /* Handle middle mouse button restarts of drawing mode. If not in | a drawing mode, middle mouse button will select objects. */ if (Settings.Mode == LINE_MODE && Crosshair.AttachedLine.State != STATE_FIRST) { SetMode (LINE_MODE); } else if (Settings.Mode == ARC_MODE && Crosshair.AttachedBox.State != STATE_FIRST) SetMode (ARC_MODE); else if (Settings.Mode == RECTANGLE_MODE && Crosshair.AttachedBox.State != STATE_FIRST) SetMode (RECTANGLE_MODE); else if (Settings.Mode == POLYGON_MODE && Crosshair.AttachedLine.State != STATE_FIRST) SetMode (POLYGON_MODE); else { SaveMode (); saved_mode = true; SetMode (ARROW_MODE); NotifyMode (); } break; #endif case F_Text: SetMode (TEXT_MODE); break; case F_Thermal: SetMode (THERMAL_MODE); break; case F_Via: SetMode (VIA_MODE); break; case F_Restore: /* restore the last saved mode */ RestoreMode (); break; case F_Save: /* save currently selected mode */ SaveMode (); break; } notify_crosshair_change (true); return 0; } AFAIL (mode); } /* --------------------------------------------------------------------------- */ static const char removeselected_syntax[] = N_("RemoveSelected()"); static const char removeselected_help[] = N_("Removes any selected objects."); /* %start-doc actions RemoveSelected %end-doc */ static int ActionRemoveSelected (int argc, char **argv, Coord x, Coord y) { if (RemoveSelected ()) SetChangedFlag (true); return 0; } /* --------------------------------------------------------------------------- */ static const char renumber_syntax[] = N_("Renumber()\n" "Renumber(filename)"); static const char renumber_help[] = N_("Renumber all elements. The changes will be recorded to filename\n" "for use in backannotating these changes to the schematic."); /* %start-doc actions Renumber %end-doc */ static int ActionRenumber (int argc, char **argv, Coord x, Coord y) { bool changed = false; ElementType **element_list; ElementType **locked_element_list; unsigned int i, j, k, cnt, lock_cnt; unsigned int tmpi; size_t sz; char *tmps; char *name; FILE *out; static char * default_file = NULL; size_t cnt_list_sz = 100; struct _cnt_list { char *name; unsigned int cnt; } *cnt_list; char **was, **is, *pin; unsigned int c_cnt = 0; int unique, ok; int free_name = 0; if (argc < 1) { /* * We deal with the case where name already exists in this * function so the GUI doesn't need to deal with it */ name = gui->fileselect (_("Save Renumber Annotation File As ..."), _("Choose a file to record the renumbering to.\n" "This file may be used to back annotate the\n" "change to the schematics.\n"), default_file, ".eco", "eco", 0); free_name = 1; } else name = argv[0]; if (default_file) { free (default_file); default_file = NULL; } if (name && *name) { default_file = strdup (name); } if ((out = fopen (name, "r"))) { fclose (out); if (!gui->confirm_dialog (_("File exists! Ok to overwrite?"), 0)) { if (free_name && name) free (name); return 0; } } if ((out = fopen (name, "w")) == NULL) { Message (_("Could not open %s\n"), name); if (free_name && name) free (name); return 1; } if (free_name && name) free (name); fprintf (out, "*COMMENT* PCB Annotation File\n"); fprintf (out, "*FILEVERSION* 20061031\n"); /* * Make a first pass through all of the elements and sort them out * by location on the board. While here we also collect a list of * locked elements. * * We'll actually renumber things in the 2nd pass. */ element_list = (ElementType **)calloc (PCB->Data->ElementN, sizeof (ElementType *)); locked_element_list = (ElementType **)calloc (PCB->Data->ElementN, sizeof (ElementType *)); was = (char **)calloc (PCB->Data->ElementN, sizeof (char *)); is = (char **)calloc (PCB->Data->ElementN, sizeof (char *)); if (element_list == NULL || locked_element_list == NULL || was == NULL || is == NULL) { fprintf (stderr, "calloc() failed in %s\n", __FUNCTION__); exit (1); } cnt = 0; lock_cnt = 0; ELEMENT_LOOP (PCB->Data); { if (TEST_FLAG (LOCKFLAG, element->Name) || TEST_FLAG (LOCKFLAG, element)) { /* * add to the list of locked elements which we won't try to * renumber and whose reference designators are now reserved. */ pcb_fprintf (out, "*WARN* Element \"%s\" at %$md is locked and will not be renumbered.\n", UNKNOWN (NAMEONPCB_NAME (element)), element->MarkX, element->MarkY); locked_element_list[lock_cnt] = element; lock_cnt++; } else { /* count of devices which will be renumbered */ cnt++; /* search for correct position in the list */ i = 0; while (element_list[i] && element->MarkY > element_list[i]->MarkY) i++; /* * We have found the position where we have the first element that * has the same Y value or a lower Y value. Now move forward if * needed through the X values */ while (element_list[i] && element->MarkY == element_list[i]->MarkY && element->MarkX > element_list[i]->MarkX) i++; for (j = cnt - 1; j > i; j--) { element_list[j] = element_list[j - 1]; } element_list[i] = element; } } END_LOOP; /* * Now that the elements are sorted by board position, we go through * and renumber them. */ /* * turn off the flag which requires unique names so it doesn't get * in our way. When we're done with the renumber we will have unique * names. */ unique = TEST_FLAG (UNIQUENAMEFLAG, PCB); CLEAR_FLAG (UNIQUENAMEFLAG, PCB); cnt_list = (struct _cnt_list *)calloc (cnt_list_sz, sizeof (struct _cnt_list)); for (i = 0; i < cnt; i++) { /* If there is no refdes, maybe just spit out a warning */ if (NAMEONPCB_NAME (element_list[i])) { /* figure out the prefix */ tmps = strdup (NAMEONPCB_NAME (element_list[i])); j = 0; while (tmps[j] && (tmps[j] < '0' || tmps[j] > '9') && tmps[j] != '?') j++; tmps[j] = '\0'; /* check the counter for this prefix */ for (j = 0; cnt_list[j].name && (strcmp (cnt_list[j].name, tmps) != 0) && j < cnt_list_sz; j++); /* grow the list if needed */ if (j == cnt_list_sz) { cnt_list_sz += 100; cnt_list = (struct _cnt_list *)realloc (cnt_list, cnt_list_sz); if (cnt_list == NULL) { fprintf (stderr, _("realloc() failed in %s()\n"), __FUNCTION__); exit (1); } /* zero out the memory that we added */ for (tmpi = j; tmpi < cnt_list_sz; tmpi++) { cnt_list[tmpi].name = NULL; cnt_list[tmpi].cnt = 0; } } /* * start a new counter if we don't have a counter for this * prefix */ if (!cnt_list[j].name) { cnt_list[j].name = strdup (tmps); cnt_list[j].cnt = 0; } /* * check to see if the new refdes is already used by a * locked element */ do { ok = 1; cnt_list[j].cnt++; free (tmps); /* space for the prefix plus 1 digit plus the '\0' */ sz = strlen (cnt_list[j].name) + 2; /* and 1 more per extra digit needed to hold the number */ tmpi = cnt_list[j].cnt; while (tmpi > 10) { sz++; tmpi = tmpi / 10; } tmps = (char *)malloc (sz * sizeof (char)); sprintf (tmps, "%s%d", cnt_list[j].name, (int) cnt_list[j].cnt); /* * now compare to the list of reserved (by locked * elements) names */ for (k = 0; k < lock_cnt; k++) { if (strcmp (UNKNOWN (NAMEONPCB_NAME (locked_element_list[k])), tmps) == 0) { ok = 0; break; } } } while (!ok); if (strcmp (tmps, NAMEONPCB_NAME (element_list[i])) != 0) { fprintf (out, "*RENAME* \"%s\" \"%s\"\n", NAMEONPCB_NAME (element_list[i]), tmps); /* add this rename to our table of renames so we can update the netlist */ was[c_cnt] = strdup (NAMEONPCB_NAME (element_list[i])); is[c_cnt] = strdup (tmps); c_cnt++; AddObjectToChangeNameUndoList (ELEMENT_TYPE, NULL, NULL, element_list[i], NAMEONPCB_NAME (element_list [i])); ChangeObjectName (ELEMENT_TYPE, element_list[i], NULL, NULL, tmps); changed = true; /* we don't free tmps in this case because it is used */ } else free (tmps); } else { pcb_fprintf (out, "*WARN* Element at %$md has no name.\n", element_list[i]->MarkX, element_list[i]->MarkY); } } fclose (out); /* restore the unique flag setting */ if (unique) SET_FLAG (UNIQUENAMEFLAG, PCB); if (changed) { /* update the netlist */ AddNetlistLibToUndoList (&(PCB->NetlistLib)); /* iterate over each net */ for (i = 0; i < PCB->NetlistLib.MenuN; i++) { /* iterate over each pin on the net */ for (j = 0; j < PCB->NetlistLib.Menu[i].EntryN; j++) { /* figure out the pin number part from strings like U3-21 */ tmps = strdup (PCB->NetlistLib.Menu[i].Entry[j].ListEntry); for (k = 0; tmps[k] && tmps[k] != '-'; k++); tmps[k] = '\0'; pin = tmps + k + 1; /* iterate over the list of changed reference designators */ for (k = 0; k < c_cnt; k++) { /* * if the pin needs to change, change it and quit * searching in the list. */ if (strcmp (tmps, was[k]) == 0) { free (PCB->NetlistLib.Menu[i].Entry[j].ListEntry); PCB->NetlistLib.Menu[i].Entry[j].ListEntry = (char *)malloc ((strlen (is[k]) + strlen (pin) + 2) * sizeof (char)); sprintf (PCB->NetlistLib.Menu[i].Entry[j].ListEntry, "%s-%s", is[k], pin); k = c_cnt; } } free (tmps); } } for (k = 0; k < c_cnt; k++) { free (was[k]); free (is[k]); } NetlistChanged (0); IncrementUndoSerialNumber (); SetChangedFlag (true); } free (locked_element_list); free (element_list); free (cnt_list); free (is); free (was); return 0; } /* --------------------------------------------------------------------------- */ static const char ripup_syntax[] = N_("RipUp(All|Selected|Element)"); static const char ripup_help[] = N_("Ripup auto-routed tracks, or convert an element to parts."); /* %start-doc actions RipUp @table @code @item All Removes all lines and vias which were created by the autorouter. @item Selected Removes all selected lines and vias which were created by the autorouter. @item Element Converts the element under the cursor to parts (vias and lines). Note that this uses the highest numbered paste buffer. @end table %end-doc */ static int ActionRipUp (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); bool changed = false; if (function) { switch (GetFunctionID (function)) { case F_All: ALLLINE_LOOP (PCB->Data); { if (TEST_FLAG (AUTOFLAG, line) && !TEST_FLAG (LOCKFLAG, line)) { RemoveObject (LINE_TYPE, layer, line, line); changed = true; } } ENDALL_LOOP; ALLARC_LOOP (PCB->Data); { if (TEST_FLAG (AUTOFLAG, arc) && !TEST_FLAG (LOCKFLAG, arc)) { RemoveObject (ARC_TYPE, layer, arc, arc); changed = true; } } ENDALL_LOOP; VIA_LOOP (PCB->Data); { if (TEST_FLAG (AUTOFLAG, via) && !TEST_FLAG (LOCKFLAG, via)) { RemoveObject (VIA_TYPE, via, via, via); changed = true; } } END_LOOP; if (changed) { IncrementUndoSerialNumber (); SetChangedFlag (true); } break; case F_Selected: VISIBLELINE_LOOP (PCB->Data); { if (TEST_FLAGS (AUTOFLAG | SELECTEDFLAG, line) && !TEST_FLAG (LOCKFLAG, line)) { RemoveObject (LINE_TYPE, layer, line, line); changed = true; } } ENDALL_LOOP; if (PCB->ViaOn) VIA_LOOP (PCB->Data); { if (TEST_FLAGS (AUTOFLAG | SELECTEDFLAG, via) && !TEST_FLAG (LOCKFLAG, via)) { RemoveObject (VIA_TYPE, via, via, via); changed = true; } } END_LOOP; if (changed) { IncrementUndoSerialNumber (); SetChangedFlag (true); } break; case F_Element: { void *ptr1, *ptr2, *ptr3; if (SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptr1, &ptr2, &ptr3) != NO_TYPE) { Note.Buffer = Settings.BufferNumber; SetBufferNumber (MAX_BUFFER - 1); ClearBuffer (PASTEBUFFER); CopyObjectToBuffer (PASTEBUFFER->Data, PCB->Data, ELEMENT_TYPE, ptr1, ptr2, ptr3); SmashBufferElement (PASTEBUFFER); PASTEBUFFER->X = 0; PASTEBUFFER->Y = 0; SaveUndoSerialNumber (); EraseObject (ELEMENT_TYPE, ptr1, ptr1); MoveObjectToRemoveUndoList (ELEMENT_TYPE, ptr1, ptr2, ptr3); RestoreUndoSerialNumber (); CopyPastebufferToLayout (0, 0); SetBufferNumber (Note.Buffer); SetChangedFlag (true); } } break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char addrats_syntax[] = N_("AddRats(AllRats|SelectedRats|Close)"); static const char addrats_help[] = N_("Add one or more rat lines to the board."); /* %start-doc actions AddRats @table @code @item AllRats Create rat lines for all loaded nets that aren't already connected on with copper. @item SelectedRats Similarly, but only add rat lines for nets connected to selected pins and pads. @item Close Selects the shortest unselected rat on the board. @end table %end-doc */ static int ActionAddRats (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); RatType *shorty; float len, small; if (function) { if (Settings.RatWarn) ClearWarnings (); switch (GetFunctionID (function)) { case F_AllRats: if (AddAllRats (false, NULL)) SetChangedFlag (true); break; case F_SelectedRats: case F_Selected: if (AddAllRats (true, NULL)) SetChangedFlag (true); break; case F_Close: small = SQUARE (MAX_COORD); shorty = NULL; RAT_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, line)) continue; len = SQUARE (line->Point1.X - line->Point2.X) + SQUARE (line->Point1.Y - line->Point2.Y); if (len < small) { small = len; shorty = line; } } END_LOOP; if (shorty) { AddObjectToFlagUndoList (RATLINE_TYPE, shorty, shorty, shorty); SET_FLAG (SELECTEDFLAG, shorty); DrawRat (shorty); Draw (); CenterDisplay ((shorty->Point2.X + shorty->Point1.X) / 2, (shorty->Point2.Y + shorty->Point1.Y) / 2, false); } break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char delete_syntax[] = N_("Delete(Object|Selected)\n" "Delete(AllRats|SelectedRats)"); static const char delete_help[] = N_("Delete stuff."); /* %start-doc actions Delete %end-doc */ static int ActionDelete (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); int id = GetFunctionID (function); Note.X = Crosshair.X; Note.Y = Crosshair.Y; if (id == -1) /* no arg */ { if (RemoveSelected() == false) id = F_Object; } switch (id) { case F_Object: SaveMode(); SetMode(REMOVE_MODE); NotifyMode(); RestoreMode(); break; case F_Selected: RemoveSelected(); break; case F_AllRats: if (DeleteRats (false)) SetChangedFlag (true); break; case F_SelectedRats: if (DeleteRats (true)) SetChangedFlag (true); break; } return 0; } /* --------------------------------------------------------------------------- */ static const char deleterats_syntax[] = N_("DeleteRats(AllRats|Selected|SelectedRats)"); static const char deleterats_help[] = N_("Delete rat lines."); /* %start-doc actions DeleteRats %end-doc */ static int ActionDeleteRats (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { if (Settings.RatWarn) ClearWarnings (); switch (GetFunctionID (function)) { case F_AllRats: if (DeleteRats (false)) SetChangedFlag (true); break; case F_SelectedRats: case F_Selected: if (DeleteRats (true)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char autoplace_syntax[] = N_("AutoPlaceSelected()"); static const char autoplace_help[] = N_("Auto-place selected components."); /* %start-doc actions AutoPlaceSelected Attempts to re-arrange the selected components such that the nets connecting them are minimized. Note that you cannot undo this. %end-doc */ static int ActionAutoPlaceSelected (int argc, char **argv, Coord x, Coord y) { hid_action("Busy"); if (gui->confirm_dialog (_("Auto-placement can NOT be undone.\n" "Do you want to continue anyway?\n"), 0)) { if (AutoPlaceSelected ()) SetChangedFlag (true); } return 0; } /* --------------------------------------------------------------------------- */ static const char autoroute_syntax[] = N_("AutoRoute(AllRats|SelectedRats)"); static const char autoroute_help[] = N_("Auto-route some or all rat lines."); /* %start-doc actions AutoRoute @table @code @item AllRats Attempt to autoroute all rats. @item SelectedRats Attempt to autoroute the selected rats. @end table Before autorouting, it's important to set up a few things. First, make sure any layers you aren't using are disabled, else the autorouter may use them. Next, make sure the current line and via styles are set accordingly. Last, make sure "new lines clear polygons" is set, in case you eventually want to add a copper pour. Autorouting takes a while. During this time, the program may not be responsive. %end-doc */ static int ActionAutoRoute (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); hid_action("Busy"); if (function) /* one parameter */ { switch (GetFunctionID (function)) { case F_AllRats: if (AutoRoute (false)) SetChangedFlag (true); break; case F_SelectedRats: case F_Selected: if (AutoRoute (true)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char markcrosshair_syntax[] = N_("MarkCrosshair()\n" "MarkCrosshair(Center)"); static const char markcrosshair_help[] = N_("Set/Reset the Crosshair mark."); /* %start-doc actions MarkCrosshair The ``mark'' is a small X-shaped target on the display which is treated like a second origin (the normal origin is the upper let corner of the board). The GUI will display a second set of coordinates for this mark, which tells you how far you are from it. If no argument is given, the mark is toggled - disabled if it was enabled, or enabled at the current cursor position of disabled. If the @code{Center} argument is given, the mark is moved to the current cursor location. %end-doc */ static int ActionMarkCrosshair (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (!function || !*function) { if (Marked.status) { notify_mark_change (false); Marked.status = false; notify_mark_change (true); } else { notify_mark_change (false); Marked.status = false; Marked.status = true; Marked.X = Crosshair.X; Marked.Y = Crosshair.Y; notify_mark_change (true); } } else if (GetFunctionID (function) == F_Center) { notify_mark_change (false); Marked.status = true; Marked.X = Crosshair.X; Marked.Y = Crosshair.Y; notify_mark_change (true); } return 0; } /* --------------------------------------------------------------------------- */ static const char changesize_syntax[] = N_("ChangeSize(Object, delta)\n" "ChangeSize(SelectedObjects|Selected, delta)\n" "ChangeSize(SelectedLines|SelectedPins|SelectedVias, delta)\n" "ChangeSize(SelectedPads|SelectedTexts|SelectedNames, delta)\n" "ChangeSize(SelectedElements, delta)"); static const char changesize_help[] = N_("Changes the size of objects."); /* %start-doc actions ChangeSize For lines and arcs, this changes the width. For pins and vias, this changes the overall diameter of the copper annulus. For pads, this changes the width and, indirectly, the length. For texts and names, this changes the scaling factor. For elements, this changes the width of the silk layer lines and arcs for this element. %end-doc */ static int ActionChangeSize (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *delta = ARG (1); char *units = ARG (2); bool absolute; /* indicates if absolute size is given */ Coord value; if (function && delta) { value = GetValue (delta, units, &absolute); if (value == 0) value = delta[0] == '-' ? -Settings.increments->size : Settings.increments->size; switch (GetFunctionID (function)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; if ((type = SearchScreen (Crosshair.X, Crosshair.Y, CHANGESIZE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (TEST_FLAG (LOCKFLAG, (PinType *) ptr2)) Message (_("Sorry, the object is locked\n")); if (ChangeObjectSize (type, ptr1, ptr2, ptr3, value, absolute)) SetChangedFlag (true); break; } case F_SelectedVias: if (ChangeSelectedSize (VIA_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedPins: if (ChangeSelectedSize (PIN_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedPads: if (ChangeSelectedSize (PAD_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedArcs: if (ChangeSelectedSize (ARC_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedLines: if (ChangeSelectedSize (LINE_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedTexts: if (ChangeSelectedSize (TEXT_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedNames: if (ChangeSelectedSize (ELEMENTNAME_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedElements: if (ChangeSelectedSize (ELEMENT_TYPE, value, absolute)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ChangeSelectedSize (CHANGESIZE_TYPES, value, absolute)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char changedrillsize_syntax[] = N_("ChangeDrillSize(Object, delta)\n" "ChangeDrillSize(SelectedPins|SelectedVias|Selected|SelectedObjects, delta)"); static const char changedrillsize_help[] = N_("Changes the drilling hole size of objects."); /* %start-doc actions ChangeDrillSize %end-doc */ static int ActionChange2ndSize (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *delta = ARG (1); char *units = ARG (2); bool absolute; Coord value; if (function && delta) { value = GetValue (delta, units, &absolute); switch (GetFunctionID (function)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGE2NDSIZE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (ChangeObject2ndSize (type, ptr1, ptr2, ptr3, value, absolute, true)) SetChangedFlag (true); break; } case F_SelectedVias: if (ChangeSelected2ndSize (VIA_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedPins: if (ChangeSelected2ndSize (PIN_TYPE, value, absolute)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ChangeSelected2ndSize (PIN_TYPES, value, absolute)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char changeclearsize_syntax[] = N_("ChangeClearSize(Object, delta)\n" "ChangeClearSize(SelectedPins|SelectedPads|SelectedVias, delta)\n" "ChangeClearSize(SelectedLines|SelectedArcs, delta\n" "ChangeClearSize(Selected|SelectedObjects, delta)"); static const char changeclearsize_help[] = N_("Changes the clearance size of objects."); /* %start-doc actions ChangeClearSize If the solder mask is currently showing, this action changes the solder mask clearance. If the mask is not showing, this action changes the polygon clearance. %end-doc */ static int ActionChangeClearSize (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *delta = ARG (1); char *units = ARG (2); bool absolute; Coord value; if (function && delta) { value = 2 * GetValue (delta, units, &absolute); if ((value == 0) && !absolute) value = delta[0] == '-' ? -Settings.increments->clear : Settings.increments->clear; switch (GetFunctionID (function)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGECLEARSIZE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (ChangeObjectClearSize (type, ptr1, ptr2, ptr3, value, absolute)) SetChangedFlag (true); break; } case F_SelectedVias: if (ChangeSelectedClearSize (VIA_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedPads: if (ChangeSelectedClearSize (PAD_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedPins: if (ChangeSelectedClearSize (PIN_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedLines: if (ChangeSelectedClearSize (LINE_TYPE, value, absolute)) SetChangedFlag (true); break; case F_SelectedArcs: if (ChangeSelectedClearSize (ARC_TYPE, value, absolute)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ChangeSelectedClearSize (CHANGECLEARSIZE_TYPES, value, absolute)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char minmaskgap_syntax[] = N_("MinMaskGap(delta)\n" "MinMaskGap(Selected, delta)"); static const char minmaskgap_help[] = N_("Ensures the mask is a minimum distance from pins and pads."); /* %start-doc actions MinMaskGap Checks all specified pins and/or pads, and increases the mask if needed to ensure a minimum distance between the pin or pad edge and the mask edge. %end-doc */ static int ActionMinMaskGap (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *delta = ARG (1); char *units = ARG (2); bool absolute; Coord value; Coord thickness; int flags; if (!function) return 1; if (strcasecmp (function, "Selected") == 0) flags = SELECTEDFLAG; else { units = delta; delta = function; flags = 0; } value = 2 * GetValue (delta, units, &absolute); SaveUndoSerialNumber (); ELEMENT_LOOP (PCB->Data); { PIN_LOOP (element); { if (!TEST_FLAGS (flags, pin) || ! pin->Mask) continue; thickness = pin->DrillingHole; if (pin->Thickness > thickness) thickness = pin->Thickness; thickness += value; if (pin->Mask < thickness) { ChangeObjectMaskSize (PIN_TYPE, element, pin, 0, thickness, 1); RestoreUndoSerialNumber (); } } END_LOOP; PAD_LOOP (element); { if (!TEST_FLAGS (flags, pad) || ! pad->Mask) continue; if (pad->Mask < pad->Thickness + value) { ChangeObjectMaskSize (PAD_TYPE, element, pad, 0, pad->Thickness + value, 1); RestoreUndoSerialNumber (); } } END_LOOP; } END_LOOP; VIA_LOOP (PCB->Data); { if (!TEST_FLAGS (flags, via) || ! via->Mask) continue; thickness = via->DrillingHole; if (via->Thickness > thickness) thickness = via->Thickness; thickness += value; if (via->Mask < thickness) { ChangeObjectMaskSize (VIA_TYPE, via, 0, 0, thickness, 1); RestoreUndoSerialNumber (); } } END_LOOP; RestoreUndoSerialNumber (); IncrementUndoSerialNumber (); return 0; } /* --------------------------------------------------------------------------- */ static const char mincleargap_syntax[] = N_("MinClearGap(delta)\n" "MinClearGap(Selected, delta)"); static const char mincleargap_help[] = N_("Ensures that polygons are a minimum distance from objects."); /* %start-doc actions MinClearGap Checks all specified objects, and increases the polygon clearance if needed to ensure a minimum distance between their edges and the polygon edges. %end-doc */ static int ActionMinClearGap (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *delta = ARG (1); char *units = ARG (2); bool absolute; Coord value; int flags; if (!function) return 1; if (strcasecmp (function, "Selected") == 0) flags = SELECTEDFLAG; else { units = delta; delta = function; flags = 0; } value = 2 * GetValue (delta, units, &absolute); SaveUndoSerialNumber (); ELEMENT_LOOP (PCB->Data); { PIN_LOOP (element); { if (!TEST_FLAGS (flags, pin)) continue; if (pin->Clearance < value) { ChangeObjectClearSize (PIN_TYPE, element, pin, 0, value, 1); RestoreUndoSerialNumber (); } } END_LOOP; PAD_LOOP (element); { if (!TEST_FLAGS (flags, pad)) continue; if (pad->Clearance < value) { ChangeObjectClearSize (PAD_TYPE, element, pad, 0, value, 1); RestoreUndoSerialNumber (); } } END_LOOP; } END_LOOP; VIA_LOOP (PCB->Data); { if (!TEST_FLAGS (flags, via)) continue; if (via->Clearance < value) { ChangeObjectClearSize (VIA_TYPE, via, 0, 0, value, 1); RestoreUndoSerialNumber (); } } END_LOOP; ALLLINE_LOOP (PCB->Data); { if (!TEST_FLAGS (flags, line)) continue; if (line->Clearance < value) { ChangeObjectClearSize (LINE_TYPE, layer, line, 0, value, 1); RestoreUndoSerialNumber (); } } ENDALL_LOOP; ALLARC_LOOP (PCB->Data); { if (!TEST_FLAGS (flags, arc)) continue; if (arc->Clearance < value) { ChangeObjectClearSize (ARC_TYPE, layer, arc, 0, value, 1); RestoreUndoSerialNumber (); } } ENDALL_LOOP; RestoreUndoSerialNumber (); IncrementUndoSerialNumber (); return 0; } /* --------------------------------------------------------------------------- */ static const char changepinname_syntax[] = N_("ChangePinName(ElementName,PinNumber,PinName)"); static const char changepinname_help[] = N_("Sets the name of a specific pin on a specific element."); /* %start-doc actions ChangePinName This can be especially useful for annotating pin names from a schematic to the layout without requiring knowledge of the pcb file format. @example ChangePinName(U3, 7, VCC) @end example %end-doc */ static int ActionChangePinName (int argc, char **argv, Coord x, Coord y) { int changed = 0; char *refdes, *pinnum, *pinname; if (argc != 3) { AFAIL (changepinname); } refdes = argv[0]; pinnum = argv[1]; pinname = argv[2]; ELEMENT_LOOP (PCB->Data); { if (NSTRCMP (refdes, NAMEONPCB_NAME (element)) == 0) { PIN_LOOP (element); { if (NSTRCMP (pinnum, pin->Number) == 0) { AddObjectToChangeNameUndoList (PIN_TYPE, NULL, NULL, pin, pin->Name); /* * Note: we can't free() pin->Name first because * it is used in the undo list */ pin->Name = strdup (pinname); SetChangedFlag (true); changed = 1; } } END_LOOP; PAD_LOOP (element); { if (NSTRCMP (pinnum, pad->Number) == 0) { AddObjectToChangeNameUndoList (PAD_TYPE, NULL, NULL, pad, pad->Name); /* * Note: we can't free() pad->Name first because * it is used in the undo list */ pad->Name = strdup (pinname); SetChangedFlag (true); changed = 1; } } END_LOOP; } } END_LOOP; /* * done with our action so increment the undo # if we actually * changed anything */ if (changed) { if (defer_updates) defer_needs_update = 1; else { IncrementUndoSerialNumber (); gui->invalidate_all (); } } return 0; } /* --------------------------------------------------------------------------- */ static const char changename_syntax[] = N_("ChangeName(Object)\n" "ChangeName(Layout|Layer)"); static const char changename_help[] = N_("Sets the name of objects."); /* %start-doc actions ChangeName @table @code @item Object Changes the name of the element under the cursor. @item Layout Changes the name of the layout. This is printed on the fab drawings. @item Layer Changes the name of the currently active layer. @end table %end-doc */ int ActionChangeName (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *name; if (function) { switch (GetFunctionID (function)) { /* change the name of an object */ case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGENAME_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) { SaveUndoSerialNumber (); if (QueryInputAndChangeObjectName (type, ptr1, ptr2, ptr3)) { SetChangedFlag (true); if (type == ELEMENT_TYPE) { RubberbandType *ptr; int i; RestoreUndoSerialNumber (); Crosshair.AttachedObject.RubberbandN = 0; LookupRatLines (type, ptr1, ptr2, ptr3); ptr = Crosshair.AttachedObject.Rubberband; for (i = 0; i < Crosshair.AttachedObject.RubberbandN; i++, ptr++) { if (PCB->RatOn) EraseRat ((RatType *) ptr->Line); MoveObjectToRemoveUndoList (RATLINE_TYPE, ptr->Line, ptr->Line, ptr->Line); } IncrementUndoSerialNumber (); Draw (); } } } break; } /* change the layout's name */ case F_Layout: name = gui->prompt_for (_("Enter the layout name:"), EMPTY (PCB->Name)); /* NB: ChangeLayoutName takes ownership of the passed memory */ if (name && ChangeLayoutName (name)) SetChangedFlag (true); break; /* change the name of the active layer */ case F_Layer: name = gui->prompt_for (_("Enter the layer name:"), EMPTY (CURRENT->Name)); /* NB: ChangeLayerName takes ownership of the passed memory */ if (name && ChangeLayerName (CURRENT, name)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char morphpolygon_syntax[] = N_("MorphPolygon(Object|Selected)"); static const char morphpolygon_help[] = N_("Converts dead polygon islands into separate polygons."); /* %start-doc actions MorphPolygon If a polygon is divided into unconnected "islands", you can use this command to convert the otherwise disappeared islands into separate polygons. Be sure the cursor is over a portion of the polygon that remains visible. Very small islands that may flake off are automatically deleted. %end-doc */ static int ActionMorphPolygon (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, POLYGON_TYPE, &ptr1, &ptr2, &ptr3)) != NO_TYPE) { MorphPolygon ((LayerType *) ptr1, (PolygonType *) ptr3); Draw (); IncrementUndoSerialNumber (); } break; } case F_Selected: case F_SelectedObjects: ALLPOLYGON_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, polygon)) MorphPolygon (layer, polygon); } ENDALL_LOOP; Draw (); IncrementUndoSerialNumber (); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char togglehidename_syntax[] = N_("ToggleHideName(Object|SelectedElements)"); static const char togglehidename_help[] = N_("Toggles the visibility of element names."); /* %start-doc actions ToggleHideName If names are hidden you won't see them on the screen and they will not appear on the silk layer when you print the layout. %end-doc */ static int ActionToggleHideName (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function && PCB->ElementOn) { switch (GetFunctionID (function)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, ELEMENT_TYPE, &ptr1, &ptr2, &ptr3)) != NO_TYPE) { AddObjectToFlagUndoList (type, ptr1, ptr2, ptr3); EraseElementName ((ElementType *) ptr2); TOGGLE_FLAG (HIDENAMEFLAG, (ElementType *) ptr2); DrawElementName ((ElementType *) ptr2); Draw (); IncrementUndoSerialNumber (); } break; } case F_SelectedElements: case F_Selected: { bool changed = false; ELEMENT_LOOP (PCB->Data); { if ((TEST_FLAG (SELECTEDFLAG, element) || TEST_FLAG (SELECTEDFLAG, &NAMEONPCB_TEXT (element))) && (FRONT (element) || PCB->InvisibleObjectsOn)) { AddObjectToFlagUndoList (ELEMENT_TYPE, element, element, element); EraseElementName (element); TOGGLE_FLAG (HIDENAMEFLAG, element); DrawElementName (element); changed = true; } } END_LOOP; if (changed) { Draw (); IncrementUndoSerialNumber (); } } } } return 0; } /* --------------------------------------------------------------------------- */ static const char changejoin_syntax[] = N_("ChangeJoin(ToggleObject|SelectedLines|SelectedArcs|Selected)"); static const char changejoin_help[] = N_("Changes the join (clearance through polygons) of objects."); /* %start-doc actions ChangeJoin The join flag determines whether a line or arc, drawn to intersect a polygon, electrically connects to the polygon or not. When joined, the line/arc is simply drawn over the polygon, making an electrical connection. When not joined, a gap is drawn between the line and the polygon, insulating them from each other. %end-doc */ static int ActionChangeJoin (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGEJOIN_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (ChangeObjectJoin (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedLines: if (ChangeSelectedJoin (LINE_TYPE)) SetChangedFlag (true); break; case F_SelectedArcs: if (ChangeSelectedJoin (ARC_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ChangeSelectedJoin (CHANGEJOIN_TYPES)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char changesquare_syntax[] = N_("ChangeSquare(ToggleObject)\n" "ChangeSquare(SelectedElements|SelectedPins)\n" "ChangeSquare(Selected|SelectedObjects)"); static const char changesquare_help[] = N_("Changes the square flag of pins and pads."); /* %start-doc actions ChangeSquare Note that @code{Pins} means both pins and pads. @pinshapes %end-doc */ static int ActionChangeSquare (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGESQUARE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (ChangeObjectSquare (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedElements: if (ChangeSelectedSquare (ELEMENT_TYPE)) SetChangedFlag (true); break; case F_SelectedPins: if (ChangeSelectedSquare (PIN_TYPE | PAD_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ChangeSelectedSquare (PIN_TYPE | PAD_TYPE)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char setsquare_syntax[] = N_("SetSquare(ToggleObject|SelectedElements|SelectedPins)"); static const char setsquare_help[] = N_("sets the square-flag of objects."); /* %start-doc actions SetSquare Note that @code{Pins} means pins and pads. @pinshapes %end-doc */ static int ActionSetSquare (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function && *function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGESQUARE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (SetObjectSquare (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedElements: if (SetSelectedSquare (ELEMENT_TYPE)) SetChangedFlag (true); break; case F_SelectedPins: if (SetSelectedSquare (PIN_TYPE | PAD_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (SetSelectedSquare (PIN_TYPE | PAD_TYPE)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char clearsquare_syntax[] = N_("ClearSquare(ToggleObject|SelectedElements|SelectedPins)"); static const char clearsquare_help[] = N_("Clears the square-flag of pins and pads."); /* %start-doc actions ClearSquare Note that @code{Pins} means pins and pads. @pinshapes %end-doc */ static int ActionClearSquare (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function && *function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGESQUARE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (ClrObjectSquare (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedElements: if (ClrSelectedSquare (ELEMENT_TYPE)) SetChangedFlag (true); break; case F_SelectedPins: if (ClrSelectedSquare (PIN_TYPE | PAD_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ClrSelectedSquare (PIN_TYPE | PAD_TYPE)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char changeoctagon_syntax[] = N_("ChangeOctagon(Object|ToggleObject|SelectedObjects|Selected)\n" "ChangeOctagon(SelectedElements|SelectedPins|SelectedVias)"); static const char changeoctagon_help[] = N_("Changes the octagon-flag of pins and vias."); /* %start-doc actions ChangeOctagon @pinshapes %end-doc */ static int ActionChangeOctagon (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGEOCTAGON_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (ChangeObjectOctagon (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedElements: if (ChangeSelectedOctagon (ELEMENT_TYPE)) SetChangedFlag (true); break; case F_SelectedPins: if (ChangeSelectedOctagon (PIN_TYPE)) SetChangedFlag (true); break; case F_SelectedVias: if (ChangeSelectedOctagon (VIA_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ChangeSelectedOctagon (PIN_TYPES)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char setoctagon_syntax[] = N_("SetOctagon(Object|ToggleObject|SelectedElements|Selected)"); static const char setoctagon_help[] = N_("Sets the octagon-flag of objects."); /* %start-doc actions SetOctagon @pinshapes %end-doc */ static int ActionSetOctagon (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, CHANGEOCTAGON_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (SetObjectOctagon (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedElements: if (SetSelectedOctagon (ELEMENT_TYPE)) SetChangedFlag (true); break; case F_SelectedPins: if (SetSelectedOctagon (PIN_TYPE)) SetChangedFlag (true); break; case F_SelectedVias: if (SetSelectedOctagon (VIA_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (SetSelectedOctagon (PIN_TYPES)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char clearoctagon_syntax[] = N_("ClearOctagon(ToggleObject|Object|SelectedObjects|Selected)\n" "ClearOctagon(SelectedElements|SelectedPins|SelectedVias)"); static const char clearoctagon_help[] = N_("Clears the octagon-flag of pins and vias."); /* %start-doc actions ClearOctagon @pinshapes %end-doc */ static int ActionClearOctagon (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (Crosshair.X, Crosshair.Y, CHANGEOCTAGON_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (ClrObjectOctagon (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedElements: if (ClrSelectedOctagon (ELEMENT_TYPE)) SetChangedFlag (true); break; case F_SelectedPins: if (ClrSelectedOctagon (PIN_TYPE)) SetChangedFlag (true); break; case F_SelectedVias: if (ClrSelectedOctagon (VIA_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (ClrSelectedOctagon (PIN_TYPES)) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char changehold_syntax[] = N_("ChangeHole(ToggleObject|Object|SelectedVias|Selected)"); static const char changehold_help[] = N_("Changes the hole flag of objects."); /* %start-doc actions ChangeHole The "hole flag" of a via determines whether the via is a plated-through hole (not set), or an unplated hole (set). %end-doc */ static int ActionChangeHole (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, VIA_TYPE, &ptr1, &ptr2, &ptr3)) != NO_TYPE && ChangeHole ((PinType *) ptr3)) IncrementUndoSerialNumber (); break; } case F_SelectedVias: case F_Selected: if (ChangeSelectedHole ()) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char changepaste_syntax[] = N_("ChangePaste(ToggleObject|Object|SelectedPads|Selected)"); static const char changepaste_help[] = N_("Changes the no paste flag of objects."); /* %start-doc actions ChangePaste The "no paste flag" of a pad determines whether the solderpaste stencil will have an opening for the pad (no set) or if there wil be no solderpaste on the pad (set). This is used for things such as fiducial pads. %end-doc */ static int ActionChangePaste (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_ToggleObject: case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, PAD_TYPE, &ptr1, &ptr2, &ptr3)) != NO_TYPE && ChangePaste ((PadType *) ptr3)) IncrementUndoSerialNumber (); break; } case F_SelectedPads: case F_Selected: if (ChangeSelectedPaste ()) SetChangedFlag (true); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char select_syntax[] = N_("Select(Object|ToggleObject)\n" "Select(All|Block|Connection|BuriedVias)\n" "Select(ElementByName|ObjectByName|PadByName|PinByName)\n" "Select(ElementByName|ObjectByName|PadByName|PinByName, Name)\n" "Select(TextByName|ViaByName|NetByName)\n" "Select(TextByName|ViaByName|NetByName, Name)\n" "Select(Convert)"); static const char select_help[] = N_("Toggles or sets the selection."); /* %start-doc actions Select @table @code @item ElementByName @item ObjectByName @item PadByName @item PinByName @item TextByName @item ViaByName @item NetByName These all rely on having a regular expression parser built into @code{pcb}. If the name is not specified then the user is prompted for a pattern, and all objects that match the pattern and are of the type specified are selected. @item Object @item ToggleObject Selects the object under the cursor. @item Block Selects all objects in a rectangle indicated by the cursor. @item All Selects all objects on the board. @item Found Selects all connections with the ``found'' flag set. @item Connection Selects all connections with the ``connected'' flag set. @item Connection Selects all blind and buried vias. @item Convert Converts the selected objects to an element. This uses the highest numbered paste buffer. @end table %end-doc */ static int ActionSelect (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) int type; /* select objects by their names */ case F_ElementByName: type = ELEMENT_TYPE; goto commonByName; case F_ObjectByName: type = ALL_TYPES; goto commonByName; case F_PadByName: type = PAD_TYPE; goto commonByName; case F_PinByName: type = PIN_TYPE; goto commonByName; case F_TextByName: type = TEXT_TYPE; goto commonByName; case F_ViaByName: type = VIA_TYPE; goto commonByName; case F_NetByName: type = NET_TYPE; goto commonByName; commonByName: { char *pattern = ARG (1); if (pattern || (pattern = gui->prompt_for (_("Enter pattern:"), "")) != NULL) { if (SelectObjectByName (type, pattern, true)) SetChangedFlag (true); if (ARG (1) == NULL) free (pattern); } break; } #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */ /* select a single object */ case F_ToggleObject: case F_Object: if (SelectObject ()) SetChangedFlag (true); break; /* all objects in block */ case F_Block: { BoxType box; box.X1 = MIN (Crosshair.AttachedBox.Point1.X, Crosshair.AttachedBox.Point2.X); box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y, Crosshair.AttachedBox.Point2.Y); box.X2 = MAX (Crosshair.AttachedBox.Point1.X, Crosshair.AttachedBox.Point2.X); box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y, Crosshair.AttachedBox.Point2.Y); notify_crosshair_change (false); NotifyBlock (); if (Crosshair.AttachedBox.State == STATE_THIRD && SelectBlock (&box, true)) { SetChangedFlag (true); Crosshair.AttachedBox.State = STATE_FIRST; } notify_crosshair_change (true); break; } /* select all visible objects */ case F_All: { BoxType box; box.X1 = -MAX_COORD; box.Y1 = -MAX_COORD; box.X2 = MAX_COORD; box.Y2 = MAX_COORD; if (SelectBlock (&box, true)) SetChangedFlag (true); break; } /* all logical connections */ case F_Found: if (SelectByFlag (FOUNDFLAG, true)) { Draw (); IncrementUndoSerialNumber (); SetChangedFlag (true); } break; /* all physical connections */ case F_Connection: if (SelectByFlag (CONNECTEDFLAG, true)) { Draw (); IncrementUndoSerialNumber (); SetChangedFlag (true); } break; case F_BuriedVias: if (SelectBuriedVias (true)) { Draw (); IncrementUndoSerialNumber (); SetChangedFlag (true); } break; case F_Convert: { Coord x, y; Note.Buffer = Settings.BufferNumber; SetBufferNumber (MAX_BUFFER - 1); ClearBuffer (PASTEBUFFER); gui->get_coords (_("Select the Element's Mark Location"), &x, &y); x = GridFit (x, PCB->Grid, PCB->GridOffsetX); y = GridFit (y, PCB->Grid, PCB->GridOffsetY); AddSelectedToBuffer (PASTEBUFFER, x, y, true); SaveUndoSerialNumber (); RemoveSelected (); ConvertBufferToElement (PASTEBUFFER); RestoreUndoSerialNumber (); CopyPastebufferToLayout (x, y); SetBufferNumber (Note.Buffer); } break; default: AFAIL (select); break; } } return 0; } /* FLAG(have_regex,FlagHaveRegex,0) */ int FlagHaveRegex (int parm) { #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) return 1; #else return 0; #endif } /* --------------------------------------------------------------------------- */ static const char unselect_syntax[] = N_("Unselect(All|Block|Connection)\n" "Unselect(ElementByName|ObjectByName|PadByName|PinByName)\n" "Unselect(ElementByName|ObjectByName|PadByName|PinByName, Name)\n" "Unselect(TextByName|ViaByName)\n" "Unselect(TextByName|ViaByName, Name)\n"); static const char unselect_help[] = N_("Unselects the object at the pointer location or the specified objects."); /* %start-doc actions Unselect @table @code @item All Unselect all objects. @item Block Unselect all objects in a rectangle given by the cursor. @item Connection Unselect all connections with the ``found'' flag set. @item ElementByName @item ObjectByName @item PadByName @item PinByName @item TextByName @item ViaByName These all rely on having a regular expression parser built into @code{pcb}. If the name is not specified then the user is prompted for a pattern, and all objects that match the pattern and are of the type specified are unselected. @end table %end-doc */ static int ActionUnselect (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) int type; /* select objects by their names */ case F_ElementByName: type = ELEMENT_TYPE; goto commonByName; case F_ObjectByName: type = ALL_TYPES; goto commonByName; case F_PadByName: type = PAD_TYPE; goto commonByName; case F_PinByName: type = PIN_TYPE; goto commonByName; case F_TextByName: type = TEXT_TYPE; goto commonByName; case F_ViaByName: type = VIA_TYPE; goto commonByName; case F_NetByName: type = NET_TYPE; goto commonByName; commonByName: { char *pattern = ARG (1); if (pattern || (pattern = gui->prompt_for (_("Enter pattern:"), "")) != NULL) { if (SelectObjectByName (type, pattern, false)) SetChangedFlag (true); if (ARG (1) == NULL) free (pattern); } break; } #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */ /* all objects in block */ case F_Block: { BoxType box; box.X1 = MIN (Crosshair.AttachedBox.Point1.X, Crosshair.AttachedBox.Point2.X); box.Y1 = MIN (Crosshair.AttachedBox.Point1.Y, Crosshair.AttachedBox.Point2.Y); box.X2 = MAX (Crosshair.AttachedBox.Point1.X, Crosshair.AttachedBox.Point2.X); box.Y2 = MAX (Crosshair.AttachedBox.Point1.Y, Crosshair.AttachedBox.Point2.Y); notify_crosshair_change (false); NotifyBlock (); if (Crosshair.AttachedBox.State == STATE_THIRD && SelectBlock (&box, false)) { SetChangedFlag (true); Crosshair.AttachedBox.State = STATE_FIRST; } notify_crosshair_change (true); break; } /* unselect all visible objects */ case F_All: { BoxType box; box.X1 = -MAX_COORD; box.Y1 = -MAX_COORD; box.X2 = MAX_COORD; box.Y2 = MAX_COORD; if (SelectBlock (&box, false)) SetChangedFlag (true); break; } /* all logical connections */ case F_Found: if (SelectByFlag (FOUNDFLAG, false)) { Draw (); IncrementUndoSerialNumber (); SetChangedFlag (true); } break; /* all physical connections */ case F_Connection: if (SelectByFlag (CONNECTEDFLAG, false)) { Draw (); IncrementUndoSerialNumber (); SetChangedFlag (true); } break; default: AFAIL (unselect); break; } } return 0; } /* --------------------------------------------------------------------------- */ static const char saveto_syntax[] = N_("SaveTo(Layout|LayoutAs,filename)\n" "SaveTo(AllConnections|AllUnusedPins|ElementConnections,filename)\n" "SaveTo(PasteBuffer,filename)"); static const char saveto_help[] = N_("Saves data to a file."); /* %start-doc actions SaveTo @table @code @item Layout Saves the current layout. @item LayoutAs Saves the current layout, and remembers the filename used. @item AllConnections Save all connections to a file. @item AllUnusedPins List all unused pins to a file. @item ElementConnections Save connections to the element at the cursor to a file. @item PasteBuffer Save the content of the active Buffer to a file. This is the graphical way to create a footprint. @end table %end-doc */ static int ActionSaveTo (int argc, char **argv, Coord x, Coord y) { char *function; char *name; function = ARG (0); if ( ! function || strcasecmp (function, "Layout") == 0) { if (SavePCB (PCB->Filename) == 0) SetChangedFlag (false); return 0; } if (argc != 2) AFAIL (saveto); name = argv[1]; if (strcasecmp (function, "LayoutAs") == 0) { if (SavePCB (name) == 0) { SetChangedFlag (false); free (PCB->Filename); PCB->Filename = strdup (name); if (gui->notify_filename_changed != NULL) gui->notify_filename_changed (); } return 0; } if (strcasecmp (function, "AllConnections") == 0) { FILE *fp; bool result; if ((fp = CheckAndOpenFile (name, true, false, &result, NULL)) != NULL) { LookupConnectionsToAllElements (fp); fclose (fp); SetChangedFlag (true); } return 0; } if (strcasecmp (function, "AllUnusedPins") == 0) { FILE *fp; bool result; if ((fp = CheckAndOpenFile (name, true, false, &result, NULL)) != NULL) { LookupUnusedPins (fp); fclose (fp); SetChangedFlag (true); } return 0; } if (strcasecmp (function, "ElementConnections") == 0) { ElementType *element; void *ptrtmp; FILE *fp; bool result; if ((SearchScreen (Crosshair.X, Crosshair.Y, ELEMENT_TYPE, &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE) { element = (ElementType *) ptrtmp; if ((fp = CheckAndOpenFile (name, true, false, &result, NULL)) != NULL) { LookupElementConnections (element, fp); fclose (fp); SetChangedFlag (true); } } return 0; } if (strcasecmp (function, "PasteBuffer") == 0) { return SaveBufferElements (name); } AFAIL (saveto); } /* --------------------------------------------------------------------------- */ static const char savesettings_syntax[] = N_("SaveSettings()\n" "SaveSettings(local)"); static const char savesettings_help[] = N_("Saves settings."); /* %start-doc actions SaveSettings If you pass no arguments, the settings are stored in @code{$HOME/.pcb/settings}. If you pass the word @code{local} they're saved in @code{./pcb.settings}. %end-doc */ static int ActionSaveSettings (int argc, char **argv, Coord x, Coord y) { int locally = argc > 0 ? (strncasecmp (argv[0], "local", 5) == 0) : 0; hid_save_settings (locally); return 0; } /* --------------------------------------------------------------------------- */ static const char loadfrom_syntax[] = N_("LoadFrom(Layout|LayoutToBuffer|ElementToBuffer|Netlist|Revert,filename)"); static const char loadfrom_help[] = N_("Load layout data from a file."); /* %start-doc actions LoadFrom This action assumes you know what the filename is. The various GUIs should have a similar @code{Load} action where the filename is optional, and will provide their own file selection mechanism to let you choose the file name. @table @code @item Layout Loads an entire PCB layout, replacing the current one. @item LayoutToBuffer Loads an entire PCB layout to the paste buffer. @item ElementToBuffer Loads the given element file into the paste buffer. Element files contain only a single @code{Element} definition, such as the ``newlib'' library uses. @item Netlist Loads a new netlist, replacing any current netlist. @item Revert Re-loads the current layout from its disk file, reverting any changes you may have made. @end table %end-doc */ static int ActionLoadFrom (int argc, char **argv, Coord x, Coord y) { char *function; char *name; if (argc < 2) AFAIL (loadfrom); function = argv[0]; name = argv[1]; if (strcasecmp (function, "ElementToBuffer") == 0) { notify_crosshair_change (false); if (LoadElementToBuffer (PASTEBUFFER, name, true)) SetMode (PASTEBUFFER_MODE); notify_crosshair_change (true); } else if (strcasecmp (function, "LayoutToBuffer") == 0) { notify_crosshair_change (false); if (LoadLayoutToBuffer (PASTEBUFFER, name)) SetMode (PASTEBUFFER_MODE); notify_crosshair_change (true); } else if (strcasecmp (function, "Layout") == 0) { if (!PCB->Changed || gui->confirm_dialog (_("OK to override layout data?"), 0)) LoadPCB (name); } else if (strcasecmp (function, "Netlist") == 0) { if (PCB->Netlistname) free (PCB->Netlistname); PCB->Netlistname = StripWhiteSpaceAndDup (name); FreeLibraryMemory (&PCB->NetlistLib); ImportNetlist (PCB->Netlistname); NetlistChanged (1); netlist_loaded = true; } else if (strcasecmp (function, "Revert") == 0 && PCB->Filename && (!PCB->Changed || gui->confirm_dialog (_("OK to override changes?"), 0))) { RevertPCB (); } return 0; } /* --------------------------------------------------------------------------- */ static const char new_syntax[] = N_("New([name])"); static const char new_help[] = N_("Starts a new layout."); /* %start-doc actions New If a name is not given, one is prompted for. %end-doc */ static int ActionNew (int argc, char **argv, Coord x, Coord y) { char *name = ARG (0); if (!PCB->Changed || gui->confirm_dialog (_("OK to clear layout data?"), 0)) { if (name) name = strdup (name); else name = gui->prompt_for (_("Enter the layout name:"), ""); if (!name) return 1; notify_crosshair_change (false); /* do emergency saving * clear the old struct and allocate memory for the new one */ if (PCB->Changed && Settings.SaveInTMP) SaveInTMP (); RemovePCB (PCB); PCB = NULL; PCB = CreateNewPCB (); CreateNewPCBPost (PCB, 1); /* setup the new name and reset some values to default */ free (PCB->Name); PCB->Name = name; ResetStackAndVisibility (); CenterDisplay (PCB->MaxWidth / 2, PCB->MaxHeight / 2, false); Redraw (); hid_action ("PCBChanged"); notify_crosshair_change (true); return 0; } return 1; } /*! * \brief No operation, just for testing purposes. * syntax: Bell(volume) */ void ActionBell (char *volume) { gui->beep (); } /* --------------------------------------------------------------------------- */ static const char pastebuffer_syntax[] = N_("PasteBuffer(AddSelected|Clear|1..MAX_BUFFER)\n" "PasteBuffer(Rotate, 1..3)\n" "PasteBuffer(Convert|Save|Restore|Mirror)\n" "PasteBuffer(ToLayout, X, Y, units)"); static const char pastebuffer_help[] = N_("Various operations on the paste buffer."); /* %start-doc actions PasteBuffer There are a number of paste buffers; the actual limit is a compile-time constant @code{MAX_BUFFER} in @file{globalconst.h}. It is currently @code{5}. One of these is the ``current'' paste buffer, often referred to as ``the'' paste buffer. @table @code @item AddSelected Copies the selected objects to the current paste buffer. @item Clear Remove all objects from the current paste buffer. @item Convert Convert the current paste buffer to an element. Vias are converted to pins, lines are converted to pads. @item Restore Convert any elements in the paste buffer back to vias and lines. @item Mirror Flip all objects in the paste buffer vertically (up/down flip). To mirror horizontally, combine this with rotations. @item Rotate Rotates the current buffer. The number to pass is 1..3, where 1 means 90 degrees counter clockwise, 2 means 180 degrees, and 3 means 90 degrees clockwise (270 CCW). @item Save Saves any elements in the current buffer to the indicated file. @item ToLayout Pastes any elements in the current buffer to the indicated X, Y coordinates in the layout. The @code{X} and @code{Y} are treated like @code{delta} is for many other objects. For each, if it's prefixed by @code{+} or @code{-}, then that amount is relative to the last location. Otherwise, it's absolute. Units can be @code{mil} or @code{mm}; if unspecified, units are PCB's internal units, currently 1/100 mil. @item 1..MAX_BUFFER Selects the given buffer to be the current paste buffer. @end table %end-doc */ static int ActionPasteBuffer (int argc, char **argv, Coord x, Coord y) { char *function = argc ? argv[0] : (char *)""; char *sbufnum = argc > 1 ? argv[1] : (char *)""; char *name; static char *default_file = NULL; int free_name = 0; notify_crosshair_change (false); if (function) { switch (GetFunctionID (function)) { /* clear contents of paste buffer */ case F_Clear: ClearBuffer (PASTEBUFFER); break; /* copies objects to paste buffer */ case F_AddSelected: AddSelectedToBuffer (PASTEBUFFER, 0, 0, false); break; /* converts buffer contents into an element */ case F_Convert: ConvertBufferToElement (PASTEBUFFER); break; /* break up element for editing */ case F_Restore: SmashBufferElement (PASTEBUFFER); break; /* Mirror buffer */ case F_Mirror: MirrorBuffer (PASTEBUFFER); break; case F_Rotate: if (sbufnum) { RotateBuffer (PASTEBUFFER, (BYTE) atoi (sbufnum)); crosshair_update_range(); } break; case F_Save: if (PASTEBUFFER->Data->ElementN == 0) { Message (_("Buffer has no elements!\n")); break; } free_name = 0; if (argc <= 1) { name = gui->fileselect (_("Save Paste Buffer As ..."), _("Choose a file to save the contents of the\n" "paste buffer to.\n"), default_file, ".fp", "footprint", 0); if (default_file) { free (default_file); default_file = NULL; } if ( name && *name) { default_file = strdup (name); } free_name = 1; } else name = argv[1]; { FILE *exist; if ((exist = fopen (name, "r"))) { fclose (exist); if (gui-> confirm_dialog (_("File exists! Ok to overwrite?"), 0)) SaveBufferElements (name); } else SaveBufferElements (name); if (free_name && name) free (name); } break; case F_ToLayout: { static Coord oldx = 0, oldy = 0; Coord x, y; bool absolute; if (argc == 1) { x = y = 0; } else if (argc == 3 || argc == 4) { x = GetValue (ARG (1), ARG (3), &absolute); if (!absolute) x += oldx; y = GetValue (ARG (2), ARG (3), &absolute); if (!absolute) y += oldy; } else { notify_crosshair_change (true); AFAIL (pastebuffer); } oldx = x; oldy = y; if (CopyPastebufferToLayout (x, y)) SetChangedFlag (true); } break; /* set number */ default: { int number = atoi (function); /* correct number */ if (number) SetBufferNumber (number - 1); } } } notify_crosshair_change (true); return 0; } /* --------------------------------------------------------------------------- */ static const char undo_syntax[] = N_("Undo()\n" "Undo(ClearList)"); static const char undo_help[] = N_("Undo recent changes."); /* %start-doc actions Undo The unlimited undo feature of @code{Pcb} allows you to recover from most operations that materially affect you work. Calling @code{Undo()} without any parameter recovers from the last (non-undo) operation. @code{ClearList} is used to release the allocated memory. @code{ClearList} is called whenever a new layout is started or loaded. See also @code{Redo} and @code{Atomic}. Note that undo groups operations by serial number; changes with the same serial number will be undone (or redone) as a group. See @code{Atomic}. %end-doc */ static int ActionUndo (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (!function || !*function) { /* don't allow undo in the middle of an operation */ if (Settings.Mode != POLYGONHOLE_MODE && Crosshair.AttachedObject.State != STATE_FIRST) return 1; if (Crosshair.AttachedBox.State != STATE_FIRST && Settings.Mode != ARC_MODE) return 1; /* undo the last operation */ notify_crosshair_change (false); if ((Settings.Mode == POLYGON_MODE || Settings.Mode == POLYGONHOLE_MODE) && Crosshair.AttachedPolygon.PointN) { GoToPreviousPoint (); notify_crosshair_change (true); return 0; } /* move anchor point if undoing during line creation */ if (Settings.Mode == LINE_MODE) { if (Crosshair.AttachedLine.State == STATE_SECOND) { if (TEST_FLAG (AUTODRCFLAG, PCB)) Undo (true); /* undo the connection find */ Crosshair.AttachedLine.State = STATE_FIRST; SetLocalRef (0, 0, false); notify_crosshair_change (true); return 0; } if (Crosshair.AttachedLine.State == STATE_THIRD) { int type; void *ptr1, *ptr3, *ptrtmp; LineType *ptr2; /* this search is guaranteed to succeed */ SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1, &ptrtmp, &ptr3, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, 0); ptr2 = (LineType *) ptrtmp; /* save both ends of line */ Crosshair.AttachedLine.Point2.X = ptr2->Point1.X; Crosshair.AttachedLine.Point2.Y = ptr2->Point1.Y; if ((type = Undo (true))) SetChangedFlag (true); /* check that the undo was of the right type */ if ((type & UNDO_CREATE) == 0) { /* wrong undo type, restore anchor points */ Crosshair.AttachedLine.Point2.X = Crosshair.AttachedLine.Point1.X; Crosshair.AttachedLine.Point2.Y = Crosshair.AttachedLine.Point1.Y; notify_crosshair_change (true); return 0; } /* move to new anchor */ Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y; /* check if an intermediate point was removed */ if (type & UNDO_REMOVE) { /* this search should find the restored line */ SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1, &ptrtmp, &ptr3, Crosshair.AttachedLine.Point2.X, Crosshair.AttachedLine.Point2.Y, 0); ptr2 = (LineType *) ptrtmp; if (TEST_FLAG (AUTODRCFLAG, PCB)) { /* undo loses CONNECTEDFLAG and FOUNDFLAG */ SET_FLAG(CONNECTEDFLAG, ptr2); SET_FLAG(FOUNDFLAG, ptr2); DrawLine (CURRENT, ptr2); } Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X = ptr2->Point2.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y = ptr2->Point2.Y; } FitCrosshairIntoGrid (Crosshair.X, Crosshair.Y); AdjustAttachedObjects (); if (--addedLines == 0) { Crosshair.AttachedLine.State = STATE_SECOND; lastLayer = CURRENT; } else { /* this search is guaranteed to succeed too */ SearchObjectByLocation (LINE_TYPE | RATLINE_TYPE, &ptr1, &ptrtmp, &ptr3, Crosshair.AttachedLine.Point1.X, Crosshair.AttachedLine.Point1.Y, 0); ptr2 = (LineType *) ptrtmp; lastLayer = (LayerType *) ptr1; } notify_crosshair_change (true); return 0; } } if (Settings.Mode == ARC_MODE) { if (Crosshair.AttachedBox.State == STATE_SECOND) { Crosshair.AttachedBox.State = STATE_FIRST; notify_crosshair_change (true); return 0; } if (Crosshair.AttachedBox.State == STATE_THIRD) { void *ptr1, *ptr2, *ptr3; BoxType *bx; /* guaranteed to succeed */ SearchObjectByLocation (ARC_TYPE, &ptr1, &ptr2, &ptr3, Crosshair.AttachedBox.Point1.X, Crosshair.AttachedBox.Point1.Y, 0); bx = GetArcEnds ((ArcType *) ptr2); Crosshair.AttachedBox.Point1.X = Crosshair.AttachedBox.Point2.X = bx->X1; Crosshair.AttachedBox.Point1.Y = Crosshair.AttachedBox.Point2.Y = bx->Y1; AdjustAttachedObjects (); if (--addedLines == 0) Crosshair.AttachedBox.State = STATE_SECOND; } } /* undo the last destructive operation */ if (Undo (true)) SetChangedFlag (true); } else if (function) { switch (GetFunctionID (function)) { /* clear 'undo objects' list */ case F_ClearList: ClearUndoList (false); break; } } notify_crosshair_change (true); return 0; } /* --------------------------------------------------------------------------- */ static const char redo_syntax[] = N_("Redo()"); static const char redo_help[] = N_("Redo recent \"undo\" operations."); /* %start-doc actions Redo This routine allows you to recover from the last undo command. You might want to do this if you thought that undo was going to revert something other than what it actually did (in case you are confused about which operations are un-doable), or if you have been backing up through a long undo list and over-shoot your stopping point. Any change that is made since the undo in question will trim the redo list. For example if you add ten lines, then undo three of them you could use redo to put them back, but if you move a line on the board before performing the redo, you will lose the ability to "redo" the three "undone" lines. %end-doc */ static int ActionRedo (int argc, char **argv, Coord x, Coord y) { if (((Settings.Mode == POLYGON_MODE || Settings.Mode == POLYGONHOLE_MODE) && Crosshair.AttachedPolygon.PointN) || Crosshair.AttachedLine.State == STATE_SECOND) return 1; notify_crosshair_change (false); if (Redo (true)) { SetChangedFlag (true); if (Settings.Mode == LINE_MODE && Crosshair.AttachedLine.State != STATE_FIRST) { LineType *line = g_list_last (CURRENT->Line)->data; Crosshair.AttachedLine.Point1.X = Crosshair.AttachedLine.Point2.X = line->Point2.X; Crosshair.AttachedLine.Point1.Y = Crosshair.AttachedLine.Point2.Y = line->Point2.Y; addedLines++; } } notify_crosshair_change (true); return 0; } /* --------------------------------------------------------------------------- */ static const char polygon_syntax[] = N_("Polygon(Close|PreviousPoint)"); static const char polygon_help[] = N_("Some polygon related stuff."); /* %start-doc actions Polygon Polygons need a special action routine to make life easier. @table @code @item Close Creates the final segment of the polygon. This may fail if clipping to 45 degree lines is switched on, in which case a warning is issued. @item PreviousPoint Resets the newly entered corner to the previous one. The Undo action will call Polygon(PreviousPoint) when appropriate to do so. @end table %end-doc */ static int ActionPolygon (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function && Settings.Mode == POLYGON_MODE) { notify_crosshair_change (false); switch (GetFunctionID (function)) { /* close open polygon if possible */ case F_Close: ClosePolygon (); break; /* go back to the previous point */ case F_PreviousPoint: GoToPreviousPoint (); break; } notify_crosshair_change (true); } return 0; } /* --------------------------------------------------------------------------- */ static const char routestyle_syntax[] = N_("RouteStyle(1|2|3|4)"); static const char routestyle_help[] = N_("Copies the indicated routing style into the current sizes."); /* %start-doc actions RouteStyle %end-doc */ static int ActionRouteStyle (int argc, char **argv, Coord x, Coord y) { char *str = ARG (0); RouteStyleType *rts; int number; if (str) { number = atoi (str); if (number > 0 && number <= NUM_STYLES) { rts = &PCB->RouteStyle[number - 1]; SetLineSize (rts->Thick); SetViaSize (rts->Diameter, true); SetViaDrillingHole (rts->Hole, true); SetKeepawayWidth (rts->Keepaway); SetViaMaskAperture(rts->ViaMask); hid_action("RouteStylesChanged"); } } return 0; } /* --------------------------------------------------------------------------- */ static const char moveobject_syntax[] = N_("MoveObject(X,Y,dim)"); static const char moveobject_help[] = N_("Moves the object under the crosshair."); /* %start-doc actions MoveObject The @code{X} and @code{Y} are treated like @code{delta} is for many other objects. For each, if it's prefixed by @code{+} or @code{-}, then that amount is relative. Otherwise, it's absolute. Units can be @code{mil} or @code{mm}; if unspecified, units are PCB's internal units, currently 1/100 mil. %end-doc */ static int ActionMoveObject (int argc, char **argv, Coord x, Coord y) { char *x_str = ARG (0); char *y_str = ARG (1); char *units = ARG (2); Coord nx, ny; bool absolute1, absolute2; void *ptr1, *ptr2, *ptr3; int type; ny = GetValue (y_str, units, &absolute1); nx = GetValue (x_str, units, &absolute2); type = SearchScreen (x, y, MOVE_TYPES, &ptr1, &ptr2, &ptr3); if (type == NO_TYPE) { Message (_("Nothing found under crosshair\n")); return 1; } if (absolute1) nx -= x; if (absolute2) ny -= y; Crosshair.AttachedObject.RubberbandN = 0; if (TEST_FLAG (RUBBERBANDFLAG, PCB)) LookupRubberbandLines (type, ptr1, ptr2, ptr3); if (type == ELEMENT_TYPE) LookupRatLines (type, ptr1, ptr2, ptr3); MoveObjectAndRubberband (type, ptr1, ptr2, ptr3, nx, ny); SetChangedFlag (true); return 0; } /* --------------------------------------------------------------------------- */ static const char movetocurrentlayer_syntax[] = N_("MoveToCurrentLayer(Object|SelectedObjects)"); static const char movetocurrentlayer_help[] = N_("Moves objects to the current layer."); /* %start-doc actions MoveToCurrentLayer Note that moving an element from a component layer to a solder layer, or from solder to component, won't automatically flip it. Use the @code{Flip()} action to do that. %end-doc */ static int ActionMoveToCurrentLayer (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); if (function) { switch (GetFunctionID (function)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; gui->get_coords (_("Select an Object"), &x, &y); if ((type = SearchScreen (x, y, MOVETOLAYER_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (MoveObjectToLayer (type, ptr1, ptr2, ptr3, CURRENT, false)) SetChangedFlag (true); break; } case F_SelectedObjects: case F_Selected: if (MoveSelectedObjectsToLayer (CURRENT)) SetChangedFlag (true); break; } } return 0; } static const char setsame_syntax[] = N_("SetSame()"); static const char setsame_help[] = N_("Sets current layer and sizes to match indicated item."); /* %start-doc actions SetSame When invoked over any line, arc, polygon, or via, this changes the current layer to be the layer that item is on, and changes the current sizes (thickness, keepaway, drill, etc) according to that item. %end-doc */ static int ActionSetSame (int argc, char **argv, Coord x, Coord y) { void *ptr1, *ptr2, *ptr3; int type; LayerType *layer = CURRENT; type = SearchScreen (x, y, CLONE_TYPES, &ptr1, &ptr2, &ptr3); /* set layer current and size from line or arc */ switch (type) { case LINE_TYPE: notify_crosshair_change (false); Settings.LineThickness = ((LineType *) ptr2)->Thickness; Settings.Keepaway = ((LineType *) ptr2)->Clearance / 2; layer = (LayerType *) ptr1; if (Settings.Mode != LINE_MODE) SetMode (LINE_MODE); notify_crosshair_change (true); hid_action ("RouteStylesChanged"); break; case ARC_TYPE: notify_crosshair_change (false); Settings.LineThickness = ((ArcType *) ptr2)->Thickness; Settings.Keepaway = ((ArcType *) ptr2)->Clearance / 2; layer = (LayerType *) ptr1; if (Settings.Mode != ARC_MODE) SetMode (ARC_MODE); notify_crosshair_change (true); hid_action ("RouteStylesChanged"); break; case POLYGON_TYPE: layer = (LayerType *) ptr1; break; case VIA_TYPE: notify_crosshair_change (false); Settings.ViaThickness = ((PinType *) ptr2)->Thickness; Settings.ViaDrillingHole = ((PinType *) ptr2)->DrillingHole; Settings.Keepaway = ((PinType *) ptr2)->Clearance / 2; if (Settings.Mode != VIA_MODE) SetMode (VIA_MODE); notify_crosshair_change (true); hid_action ("RouteStylesChanged"); break; default: return 1; } if (layer != CURRENT) { ChangeGroupVisibility (GetLayerNumber (PCB->Data, layer), true, true); Redraw (); } return 0; } /* --------------------------------------------------------------------------- */ static const char setflag_syntax[] = N_("SetFlag(Object|Selected|SelectedObjects, flag)\n" "SetFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n" "SetFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n" "SetFlag(SelectedElements, flag)\n" "flag = square | octagon | thermal | join"); static const char setflag_help[] = N_("Sets flags on objects."); /* %start-doc actions SetFlag Turns the given flag on, regardless of its previous setting. See @code{ChangeFlag}. @example SetFlag(SelectedPins,thermal) @end example %end-doc */ static int ActionSetFlag (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *flag = ARG (1); ChangeFlag (function, flag, 1, "SetFlag"); return 0; } /* --------------------------------------------------------------------------- */ static const char clrflag_syntax[] = N_("ClrFlag(Object|Selected|SelectedObjects, flag)\n" "ClrFlag(SelectedLines|SelectedPins|SelectedVias, flag)\n" "ClrFlag(SelectedPads|SelectedTexts|SelectedNames, flag)\n" "ClrFlag(SelectedElements, flag)\n" "flag = square | octagon | thermal | join"); static const char clrflag_help[] = N_("Clears flags on objects."); /* %start-doc actions ClrFlag Turns the given flag off, regardless of its previous setting. See @code{ChangeFlag}. @example ClrFlag(SelectedLines,join) @end example %end-doc */ static int ActionClrFlag (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *flag = ARG (1); ChangeFlag (function, flag, 0, "ClrFlag"); return 0; } /* --------------------------------------------------------------------------- */ static const char changeflag_syntax[] = N_("ChangeFlag(Object|Selected|SelectedObjects, flag, value)\n" "ChangeFlag(SelectedLines|SelectedPins|SelectedVias, flag, value)\n" "ChangeFlag(SelectedPads|SelectedTexts|SelectedNames, flag, value)\n" "ChangeFlag(SelectedElements, flag, value)\n" "flag = square | octagon | thermal | join\n" "value = 0 | 1"); static const char changeflag_help[] = N_("Sets or clears flags on objects."); /* %start-doc actions ChangeFlag Toggles the given flag on the indicated object(s). The flag may be one of the flags listed above (square, octagon, thermal, join). The value may be the number 0 or 1. If the value is 0, the flag is cleared. If the value is 1, the flag is set. %end-doc */ static int ActionChangeFlag (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *flag = ARG (1); int value = argc > 2 ? atoi (argv[2]) : -1; if (value != 0 && value != 1) AFAIL (changeflag); ChangeFlag (function, flag, value, "ChangeFlag"); return 0; } static void ChangeFlag (char *what, char *flag_name, int value, char *cmd_name) { bool (*set_object) (int, void *, void *, void *); bool (*set_selected) (int); if (NSTRCMP (flag_name, "square") == 0) { set_object = value ? SetObjectSquare : ClrObjectSquare; set_selected = value ? SetSelectedSquare : ClrSelectedSquare; } else if (NSTRCMP (flag_name, "octagon") == 0) { set_object = value ? SetObjectOctagon : ClrObjectOctagon; set_selected = value ? SetSelectedOctagon : ClrSelectedOctagon; } else if (NSTRCMP (flag_name, "join") == 0) { /* Note: these are backwards, because the flag is "clear" but the command is "join". */ set_object = value ? ClrObjectJoin : SetObjectJoin; set_selected = value ? ClrSelectedJoin : SetSelectedJoin; } else { Message (_("%s(): Flag \"%s\" is not valid\n"), cmd_name, flag_name); return; } switch (GetFunctionID (what)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; if ((type = SearchScreen (Crosshair.X, Crosshair.Y, CHANGESIZE_TYPES, &ptr1, &ptr2, &ptr3)) != NO_TYPE) if (TEST_FLAG (LOCKFLAG, (PinType *) ptr2)) Message (_("Sorry, the object is locked\n")); if (set_object (type, ptr1, ptr2, ptr3)) SetChangedFlag (true); break; } case F_SelectedVias: if (set_selected (VIA_TYPE)) SetChangedFlag (true); break; case F_SelectedPins: if (set_selected (PIN_TYPE)) SetChangedFlag (true); break; case F_SelectedPads: if (set_selected (PAD_TYPE)) SetChangedFlag (true); break; case F_SelectedLines: if (set_selected (LINE_TYPE)) SetChangedFlag (true); break; case F_SelectedTexts: if (set_selected (TEXT_TYPE)) SetChangedFlag (true); break; case F_SelectedNames: if (set_selected (ELEMENTNAME_TYPE)) SetChangedFlag (true); break; case F_SelectedElements: if (set_selected (ELEMENT_TYPE)) SetChangedFlag (true); break; case F_Selected: case F_SelectedObjects: if (set_selected (CHANGESIZE_TYPES)) SetChangedFlag (true); break; } } /* --------------------------------------------------------------------------- */ static const char executefile_syntax[] = N_("ExecuteFile(filename)"); static const char executefile_help[] = N_("Run actions from the given file."); /* %start-doc actions ExecuteFile Lines starting with @code{#} are ignored. %end-doc */ static int ActionExecuteFile (int argc, char **argv, Coord x, Coord y) { FILE *fp; char *fname; char line[256]; int n = 0; char *sp; if (argc != 1) AFAIL (executefile); fname = argv[0]; if ((fp = fopen (fname, "r")) == NULL) { fprintf (stderr, _("Could not open actions file \"%s\".\n"), fname); return 1; } defer_updates = 1; defer_needs_update = 0; while (fgets (line, sizeof (line), fp) != NULL) { n++; sp = line; /* eat the trailing newline */ while (*sp && *sp != '\r' && *sp != '\n') sp++; *sp = '\0'; /* eat leading spaces and tabs */ sp = line; while (*sp && (*sp == ' ' || *sp == '\t')) sp++; /* * if we have anything left and its not a comment line * then execute it */ if (*sp && *sp != '#') { /*Message ("%s : line %-3d : \"%s\"\n", fname, n, sp);*/ hid_parse_actions (sp); } } defer_updates = 0; if (defer_needs_update) { IncrementUndoSerialNumber (); gui->invalidate_all (); } fclose (fp); return 0; } /* --------------------------------------------------------------------------- */ static int ActionPSCalib (int argc, char **argv, Coord x, Coord y) { HID *ps = hid_find_exporter ("ps"); ps->calibrate (0.0,0.0); return 0; } /* --------------------------------------------------------------------------- */ static ElementType *element_cache = NULL; static ElementType * find_element_by_refdes (char *refdes) { if (element_cache && NAMEONPCB_NAME(element_cache) && strcmp (NAMEONPCB_NAME(element_cache), refdes) == 0) return element_cache; ELEMENT_LOOP (PCB->Data); { if (NAMEONPCB_NAME(element) && strcmp (NAMEONPCB_NAME(element), refdes) == 0) { element_cache = element; return element_cache; } } END_LOOP; return NULL; } static AttributeType * lookup_attr (AttributeListType *list, const char *name) { int i; for (i=0; iNumber; i++) if (strcmp (list->List[i].name, name) == 0) return & list->List[i]; return NULL; } static void delete_attr (AttributeListType *list, AttributeType *attr) { int idx = attr - list->List; if (idx < 0 || idx >= list->Number) return; if (list->Number - idx > 1) memmove (attr, attr+1, (list->Number - idx - 1) * sizeof(AttributeType)); list->Number --; } /* ---------------------------------------------------------------- */ static const char elementlist_syntax[] = N_("ElementList(Start|Done|Need,,,)"); static const char elementlist_help[] = N_("Adds the given element if it doesn't already exist."); /* %start-doc actions elementlist @table @code @item Start Indicates the start of an element list; call this before any Need actions. @item Need Searches the board for an element with a matching refdes. If found, the value and footprint are updated. If not found, a new element is created with the given footprint and value. @item Done Compares the list of elements needed since the most recent @code{start} with the list of elements actually on the board. Any elements that weren't listed are selected, so that the user may delete them. @end table %end-doc */ static int number_of_footprints_not_found; static int parse_layout_attribute_units (char *name, int def) { const char *as = AttributeGet (PCB, name); if (!as) return def; return GetValue (as, NULL, NULL); } static int ActionElementList (int argc, char **argv, Coord x, Coord y) { ElementType *e = NULL; char *refdes, *value, *footprint, *old; char *args[3]; char *function; if (argc < 1) AFAIL (elementlist); function = argv[0]; #ifdef DEBUG printf("Entered ActionElementList, executing function %s\n", function); #endif if (strcasecmp (function, "start") == 0) { ELEMENT_LOOP (PCB->Data); { CLEAR_FLAG (FOUNDFLAG, element); } END_LOOP; element_cache = NULL; number_of_footprints_not_found = 0; return 0; } if (strcasecmp (function, "done") == 0) { ELEMENT_LOOP (PCB->Data); { if (TEST_FLAG (FOUNDFLAG, element)) { CLEAR_FLAG (FOUNDFLAG, element); } else if (! EMPTY_STRING_P (NAMEONPCB_NAME (element))) { /* Unnamed elements should remain untouched */ SET_FLAG (SELECTEDFLAG, element); } } END_LOOP; if (number_of_footprints_not_found > 0) gui->confirm_dialog (_("Not all requested footprints were found.\n" "See the message log for details"), "Ok", NULL); return 0; } if (strcasecmp (function, "need") != 0) AFAIL (elementlist); if (argc != 4) AFAIL (elementlist); argc --; argv ++; refdes = ARG(0); footprint = ARG(1); value = ARG(2); args[0] = footprint; args[1] = refdes; args[2] = value; #ifdef DEBUG printf(" ... footprint = %s\n", footprint); printf(" ... refdes = %s\n", refdes); printf(" ... value = %s\n", value); #endif e = find_element_by_refdes (refdes); if (!e) { Coord nx, ny, d; #ifdef DEBUG printf(" ... Footprint not on board, need to add it.\n"); #endif /* Not on board, need to add it. */ if (LoadFootprint(argc, args, x, y)) { number_of_footprints_not_found ++; return 1; } nx = PCB->MaxWidth / 2; ny = PCB->MaxHeight / 2; d = MIN (PCB->MaxWidth, PCB->MaxHeight) / 10; nx = parse_layout_attribute_units ("import::newX", nx); ny = parse_layout_attribute_units ("import::newY", ny); d = parse_layout_attribute_units ("import::disperse", d); if (d > 0) { nx += rand () % (d*2) - d; ny += rand () % (d*2) - d; } if (nx < 0) nx = 0; if (nx >= PCB->MaxWidth) nx = PCB->MaxWidth - 1; if (ny < 0) ny = 0; if (ny >= PCB->MaxHeight) ny = PCB->MaxHeight - 1; /* Place components onto center of board. */ if (CopyPastebufferToLayout (nx, ny)) SetChangedFlag (true); } else if (e && DESCRIPTION_NAME(e) && strcmp (DESCRIPTION_NAME(e), footprint) != 0) { int er, pr, i; Coord mx, my; ElementType *pe; #ifdef DEBUG printf(" ... Footprint on board, but different from footprint loaded.\n"); #endif /* Different footprint, we need to swap them out. */ if (LoadFootprint(argc, args, x, y)) { number_of_footprints_not_found ++; return 1; } er = ElementOrientation (e); pe = PASTEBUFFER->Data->Element->data; if (!FRONT (e)) MirrorElementCoordinates (PASTEBUFFER->Data, pe, pe->MarkY*2 - PCB->MaxHeight); pr = ElementOrientation (pe); mx = e->MarkX; my = e->MarkY; if (er != pr) RotateElementLowLevel (PASTEBUFFER->Data, pe, pe->MarkX, pe->MarkY, (er-pr+4)%4); for (i=0; iName[i].X = e->Name[i].X - mx + pe->MarkX ; pe->Name[i].Y = e->Name[i].Y - my + pe->MarkY ; pe->Name[i].Direction = e->Name[i].Direction; pe->Name[i].Scale = e->Name[i].Scale; } RemoveElement (e); if (CopyPastebufferToLayout (mx, my)) SetChangedFlag (true); } /* Now reload footprint */ element_cache = NULL; e = find_element_by_refdes (refdes); old = ChangeElementText (PCB, PCB->Data, e, NAMEONPCB_INDEX, strdup (refdes)); if (old) free(old); old = ChangeElementText (PCB, PCB->Data, e, VALUE_INDEX, strdup (value)); if (old) free(old); SET_FLAG (FOUNDFLAG, e); #ifdef DEBUG printf(" ... Leaving ActionElementList.\n"); #endif return 0; } /* ---------------------------------------------------------------- */ static const char elementsetattr_syntax[] = N_("ElementSetAttr(refdes,name[,value])"); static const char elementsetattr_help[] = N_("Sets or clears an element-specific attribute."); /* %start-doc actions elementsetattr If a value is specified, the named attribute is added (if not already present) or changed (if it is) to the given value. If the value is not specified, the given attribute is removed if present. %end-doc */ static int ActionElementSetAttr (int argc, char **argv, Coord x, Coord y) { ElementType *e = NULL; char *refdes, *name, *value; AttributeType *attr; if (argc < 2) { AFAIL (elementsetattr); } refdes = argv[0]; name = argv[1]; value = ARG(2); ELEMENT_LOOP (PCB->Data); { if (NSTRCMP (refdes, NAMEONPCB_NAME (element)) == 0) { e = element; break; } } END_LOOP; if (!e) { Message(_("Cannot change attribute of %s - element not found\n"), refdes); return 1; } attr = lookup_attr (&e->Attributes, name); if (attr && value) { free (attr->value); attr->value = strdup (value); } if (attr && ! value) { delete_attr (& e->Attributes, attr); } if (!attr && value) { CreateNewAttribute (& e->Attributes, name, value); } return 0; } /* ---------------------------------------------------------------- */ static const char execcommand_syntax[] = N_("ExecCommand(command)"); static const char execcommand_help[] = N_("Runs a command."); /* %start-doc actions execcommand Runs the given command, which is a system executable. %end-doc */ static int ActionExecCommand (int argc, char **argv, Coord x, Coord y) { char *command; if (argc < 1) { AFAIL (execcommand); } command = ARG(0); if (system (command)) return 1; return 0; } /* ---------------------------------------------------------------- */ static int pcb_spawnvp (char **argv) { #ifdef HAVE__SPAWNVP int result = _spawnvp (_P_WAIT, argv[0], (const char * const *) argv); if (result == -1) return 1; else return 0; #else int pid; pid = fork (); if (pid < 0) { /* error */ Message(_("Cannot fork!")); return 1; } else if (pid == 0) { /* Child */ execvp (argv[0], argv); exit(1); } else { int rv; /* Parent */ wait (&rv); } return 0; #endif } /* ---------------------------------------------------------------- */ /*! * \brief Creates a new temporary file name. * * Hopefully the operating system provides a mkdtemp() function to * securily create a temporary directory with mode 0700.\n * If so then that directory is created and the returned string is made * up of the directory plus the name variable.\n * For example:\n * * tempfile_name_new ("myfile") might return * "/var/tmp/pcb.123456/myfile". * * If mkdtemp() is not available then 'name' is ignored and the * insecure tmpnam() function is used. * * Files/names created with tempfile_name_new() should be unlinked * with tempfile_unlink to make sure the temporary directory is also * removed when mkdtemp() is used. */ static char * tempfile_name_new (char * name) { char *tmpfile = NULL; #ifdef HAVE_MKDTEMP char *tmpdir, *mytmpdir; size_t len; #endif assert ( name != NULL ); #ifdef HAVE_MKDTEMP #define TEMPLATE "pcb.XXXXXXXX" tmpdir = getenv ("TMPDIR"); /* FIXME -- what about win32? */ if (tmpdir == NULL) { tmpdir = "/tmp"; } mytmpdir = (char *) malloc (sizeof(char) * (strlen (tmpdir) + 1 + strlen (TEMPLATE) + 1)); if (mytmpdir == NULL) { fprintf (stderr, "%s(): malloc failed()\n", __FUNCTION__); exit (1); } *mytmpdir = '\0'; (void)strcat (mytmpdir, tmpdir); (void)strcat (mytmpdir, PCB_DIR_SEPARATOR_S); (void)strcat (mytmpdir, TEMPLATE); if (mkdtemp (mytmpdir) == NULL) { fprintf (stderr, "%s(): mkdtemp (\"%s\") failed\n", __FUNCTION__, mytmpdir); free (mytmpdir); return NULL; } len = strlen (mytmpdir) + /* the temp directory name */ 1 + /* the directory sep. */ strlen (name) + /* the file name */ 1 /* the \0 termination */ ; tmpfile = (char *) malloc (sizeof (char) * len); *tmpfile = '\0'; (void)strcat (tmpfile, mytmpdir); (void)strcat (tmpfile, PCB_DIR_SEPARATOR_S); (void)strcat (tmpfile, name); free (mytmpdir); #undef TEMPLATE #else /* * tmpnam() uses a static buffer so strdup() the result right away * in case someone decides to create multiple temp names. */ tmpfile = strdup (tmpnam (NULL)); #ifdef __WIN32__ { /* Guile doesn't like \ separators */ char *c; for (c = tmpfile; *c; c++) if (*c == '\\') *c = '/'; } #endif #endif return tmpfile; } /* ---------------------------------------------------------------- */ /*! * \brief Unlink a temporary file. * * If we have mkdtemp() then our temp file lives in a temporary * directory and we need to remove that directory too. */ static int tempfile_unlink (char * name) { #ifdef DEBUG /* SDB says: Want to keep old temp files for examiniation when debugging */ return 0; #else /* DEBUG */ #ifdef HAVE_MKDTEMP int e, rc2 = 0; char *dname; unlink (name); /* it is possible that the file was never created so it is OK if the unlink fails */ /* now figure out the directory name to remove */ e = strlen (name) - 1; while (e > 0 && name[e] != PCB_DIR_SEPARATOR_C) {e--;} dname = strdup (name); dname[e] = '\0'; /* * at this point, e *should* point to the end of the directory part * but lets make sure. */ if (e > 0) { rc2 = rmdir (dname); if (rc2 != 0) { perror (dname); } } else { fprintf (stderr, _("%s(): Unable to determine temp directory name from the temp file\n"), __FUNCTION__); fprintf (stderr, "%s(): \"%s\"\n", __FUNCTION__, name); rc2 = -1; } /* name was allocated with malloc */ free (dname); free (name); /* * FIXME - should also return -1 if the temp file exists and was not * removed. */ if (rc2 != 0) { return -1; } #else /* HAVE_MKDTEMP */ int rc = unlink (name); if (rc != 0) { fprintf (stderr, _("Failed to unlink \"%s\"\n"), name); free (name); return rc; } free (name); #endif /* HAVE_MKDTEMP */ #endif /* DEBUG */ return 0; } /* ---------------------------------------------------------------- */ static const char tcad_import_syntax[] = N_("ImportTinyCAD()\n" "ImportTinyCAD(netlistfile)\n"); static const char tcad_import_help[] = N_("Import schematics from TinyCAD."); /* %start-doc actions ImportTinyCAD Imports netlist and parts from the TinyCAD. TinyCAD allows to export netlist in gEDA compatible format and part list in standard CSV format. The footprints should be defined as parameters of TinyCAD symbols. @code{Package} and @code{Footprint} parameters can be used, @code{Footprint} parameter has priority. Netlist and partlist files should have the same base name with @code{.net} and @code{.csv} extensions. During import only the netlist filename can be specified, parlist filename is derived from netlist filename by replacing @code{.net} extension by @code{.csv} extension or by adding @code{.csv} extension if netlist file does not have @code{.net} extension. @table @code @item ImportTinyCAD() Prompts the user to select netlist file. The netlist is imported, followed by partlist import. Parts are imported by sequence of @code{ElementList} actions. If existing schematics is being updated, existing parts are updated, new parts are added, removed parts are pre-selected to be easily deleted by user. @item ImportTinyCAD(netlistfile) Same as above, but specified file is used as netlist filename. @end table %end-doc */ #define CSVLEN 4096 static int ActionImportTinyCAD (int argc, char **argv, Coord x, Coord y) { netlist_loaded = false; if (argc < 2 ) { hid_actionl ("Load", "Netlist", NULL); } else { hid_actionl ("LoadFrom", "Netlist", argv[1], NULL); } if (netlist_loaded) { int l = strlen (PCB->Netlistname); char *s, *s2, *csvname = alloca(l+5); char line[CSVLEN]; FILE *f; bool header = TRUE; bool first_entry = TRUE; int maxhdr; int ix; int rhdr = -1, vhdr = -1, fhdr = -1, phdr = -1; char *rs, *vs, *fs, *ps; if (csvname == NULL) return 0; strcpy (csvname, PCB->Netlistname); if (l > 4 && strcasecmp (csvname+l-4, ".net") == 0) csvname[l-4] = '\0'; strcat(csvname, ".csv"); Message ("Importing TinyCAD Parts file (CSV): %s\n", csvname); f = fopen (csvname, "r"); if (f == NULL) return 0; fgets (line, sizeof(line), f); do { if((s = strchr (line, '\r')) != NULL) *s = '\0'; if((s = strchr (line, '\n')) != NULL) *s = '\0'; if (header) { /* Parse header line, no quotes expcted */ ix = 0; s = strtok (line, ","); while (s != NULL) { if (strcasecmp (s, "Reference") == 0) rhdr = ix; else if (strcasecmp (s, "Value") == 0) vhdr = ix; else if (strcasecmp (s, "Footprint") == 0) fhdr = ix; else if (strcasecmp (s, "Package") == 0) phdr = ix; s = strtok (NULL, ","); ix++; } if (rhdr == -1 || (fhdr == -1 && phdr == -1)) { Message ("Missing Reference and/or Footprint or Package column. Part list cannot be imported.\n"); return 0; } header = false; maxhdr = max (rhdr, max (vhdr, max (fhdr, phdr))); } else { s = line; ix = 0; rs = NULL; vs = NULL; fs = NULL; ps = NULL; while (s != NULL) { if (*s == '"') { s2 = strstr (s,"\","); if (s2 != NULL) { /* remove quote and move end pointer to conmma */ *s2 = '\0'; s2++; } else { s2 = strchr (s, '"'); } if (s2 != NULL) { /* skip leading quote */ s++; } } else s2 = strchr (s, ','); if (s2 != NULL) { *s2 = '\0'; s2++; } if (ix == rhdr) rs = s; else if (ix == vhdr) vs = s; else if (ix == fhdr) fs = s; else if (ix == phdr) ps = s; if (ix == maxhdr) break; s = s2; ix++; } if (ix == maxhdr) { char *afs; if (fs != NULL && strcmp (fs, "..") != 0 && strlen (fs) > 0) afs = fs; else if (ps != NULL && strcmp (ps, "..") != 0 && strlen (ps) > 0) afs = ps; else afs = NULL; if (afs != NULL) { if (strcmp (vs, "..") == 0) vs = ""; s = strtok (rs, ","); while (s != NULL) { #ifdef DEBUG Message ("Importing element: Refdes: \"%s\" - Value: \"%s\" - Footprint: \"%s\"\n", s, vs, afs); #endif if (first_entry) { hid_actionl("ElementList","Start", NULL); first_entry = FALSE; } hid_actionl("ElementList","Need", s, afs, vs, NULL); s = strtok (NULL, ","); } } else Message ("Element(s) \"%s\" have no Footprint or Package attribute. They cannot be imported.\n", rs); } } fgets (line, sizeof (line), f); } while (!feof (f)); fclose (f); if (!first_entry) { hid_actionl("ElementList","Done", NULL); } } return 0; } /* ---------------------------------------------------------------- */ static const char import_syntax[] = N_("Import()\n" "Import([gnetlist|make[,source,source,...]])\n" "Import(setnewpoint[,(mark|center|X,Y)])\n" "Import(setdisperse,D,units)\n"); static const char import_help[] = N_("Import schematics."); /* %start-doc actions Import Imports element and netlist data from the schematics (or some other source). The first parameter, which is optional, is the mode. If not specified, the @code{import::mode} attribute in the PCB is used. @code{gnetlist} means gnetlist is used to obtain the information from the schematics. @code{make} invokes @code{make}, assuming the user has a @code{Makefile} in the current directory. The @code{Makefile} will be invoked with the following variables set: @table @code @item PCB The name of the .pcb file @item SRCLIST A space-separated list of source files @item OUT The name of the file in which to put the command script, which may contain any @pcb{} actions. By default, this is a temporary file selected by @pcb{}, but if you specify an @code{import::outfile} attribute, that file name is used instead (and not automatically deleted afterwards). @end table The target specified to be built is the first of these that apply: @itemize @bullet @item The target specified by an @code{import::target} attribute. @item The output file specified by an @code{import::outfile} attribute. @item If nothing else is specified, the target is @code{pcb_import}. @end itemize If you specify an @code{import::makefile} attribute, then "-f " will be added to the command line. If you specify the mode, you may also specify the source files (schematics). If you do not specify any, the list of schematics is obtained by reading the @code{import::src@var{N}} attributes (like @code{import::src0}, @code{import::src1}, etc). For compatibility with future extensions to the import file format, the generated file @emph{must not} start with the two characters @code{#%}. If a temporary file is needed the @code{TMPDIR} environment variable is used to select its location. Note that the programs @code{gnetlist} and @code{make} may be overridden by the user via the @code{make-program} and @code{gnetlist} @code{pcb} settings (i.e. in @code{~/.pcb/settings} or on the command line). If @pcb{} cannot determine which schematic(s) to import from, the GUI is called to let user choose (see @code{ImportGUI()}). Note that Import() doesn't delete anything - after an Import, elements which shouldn't be on the board are selected and may be removed once it's determined that the deletion is appropriate. If @code{Import()} is called with @code{setnewpoint}, then the location of new components can be specified. This is where parts show up when they're added to the board. The default is the center of the board. @table @code @item Import(setnewpoint) Prompts the user to click on the board somewhere, uses that point. If called by a hotkey, uses the current location of the crosshair. @item Import(setnewpoint,mark) Uses the location of the mark. If no mark is present, the point is not changed. @item Import(setnewpoint,center) Resets the point to the center of the board. @item Import(setnewpoint,X,Y,units) Sets the point to the specific coordinates given. Example: @code{Import(setnewpoint,50,25,mm)} @end table Note that the X and Y locations are stored in attributes named @code{import::newX} and @code{import::newY} so you could change them manually if you wished. Calling @code{Import(setdisperse,D,units)} sets how much the newly placed elements are dispersed relative to the set point. For example, @code{Import(setdisperse,10,mm)} will offset each part randomly up to 10mm away from the point. The default dispersion is 1/10th of the smallest board dimension. Dispersion is saved in the @code{import::disperse} attribute. %end-doc */ static int ActionImport (int argc, char **argv, Coord x, Coord y) { char *mode; char **sources = NULL; int nsources = 0; #ifdef DEBUG printf("ActionImport: =========== Entering ActionImport ============\n"); #endif mode = ARG (0); if (mode && strcasecmp (mode, "setdisperse") == 0) { char *ds, *units; char buf[50]; ds = ARG (1); units = ARG (2); if (!ds) { const char *as = AttributeGet (PCB, "import::disperse"); ds = gui->prompt_for(_("Enter dispersion:"), as ? as : "0"); } if (units) { sprintf(buf, "%s%s", ds, units); AttributePut (PCB, "import::disperse", buf); } else AttributePut (PCB, "import::disperse", ds); if (ARG (1) == NULL) free (ds); return 0; } if (mode && strcasecmp (mode, "setnewpoint") == 0) { const char *xs, *ys, *units; Coord x, y; char buf[50]; xs = ARG (1); ys = ARG (2); units = ARG (3); if (!xs) { gui->get_coords (_("Click on a location"), &x, &y); } else if (strcasecmp (xs, "center") == 0) { AttributeRemove (PCB, "import::newX"); AttributeRemove (PCB, "import::newY"); return 0; } else if (strcasecmp (xs, "mark") == 0) { if (!Marked.status) return 0; x = Marked.X; y = Marked.Y; } else if (ys) { x = GetValue (xs, units, NULL); y = GetValue (ys, units, NULL); } else { Message (_("Bad syntax for Import(setnewpoint)")); return 1; } pcb_snprintf (buf, sizeof (buf), "%$ms", x); AttributePut (PCB, "import::newX", buf); pcb_snprintf (buf, sizeof (buf), "%$ms", y); AttributePut (PCB, "import::newY", buf); return 0; } if (! mode) mode = AttributeGet (PCB, "import::mode"); if (! mode) mode = "gnetlist"; if (argc > 1) { sources = argv + 1; nsources = argc - 1; } if (! sources) { char sname[40]; char *src; nsources = -1; do { nsources ++; sprintf(sname, "import::src%d", nsources); src = AttributeGet (PCB, sname); } while (src); if (nsources > 0) { sources = (char **) malloc ((nsources + 1) * sizeof (char *)); nsources = -1; do { nsources ++; sprintf(sname, "import::src%d", nsources); src = AttributeGet (PCB, sname); sources[nsources] = src; } while (src); } } if (! sources) { /* Replace .pcb with .sch and hope for the best. */ char *pcbname = PCB->Filename; char *schname; char *dot, *slash, *bslash; if (!pcbname) return hid_action("ImportGUI"); schname = (char *) malloc (strlen(pcbname) + 5); strcpy (schname, pcbname); dot = strchr (schname, '.'); slash = strchr (schname, '/'); bslash = strchr (schname, '\\'); if (dot && slash && dot < slash) dot = NULL; if (dot && bslash && dot < bslash) dot = NULL; if (dot) *dot = 0; strcat (schname, ".sch"); if (access (schname, F_OK)) { free (schname); return hid_action("ImportGUI"); } sources = (char **) malloc (2 * sizeof (char *)); sources[0] = schname; sources[1] = NULL; nsources = 1; } if (strcasecmp (mode, "gnetlist") == 0) { char *tmpfile = tempfile_name_new ("gnetlist_output"); char **cmd; int i; if (tmpfile == NULL) { Message (_("Could not create temp file")); return 1; } cmd = (char **) malloc ((7 + nsources) * sizeof (char *)); cmd[0] = Settings.GnetlistProgram; cmd[1] = "-g"; cmd[2] = "pcbfwd"; cmd[3] = "-o"; cmd[4] = tmpfile; cmd[5] = "--"; for (i=0; iedit_attributes) { Message (_("This GUI doesn't support Attribute Editing\n")); return 1; } switch (GetFunctionID (function)) { case F_Layout: { gui->edit_attributes(_("Layout Attributes"), &(PCB->Attributes)); return 0; } case F_Layer: { LayerType *layer = CURRENT; if (layername) { int i; layer = NULL; for (i=0; iData->Layer[i].Name, layername) == 0) { layer = & (PCB->Data->Layer[i]); break; } if (layer == NULL) { Message (_("No layer named %s\n"), layername); return 1; } } buf = (char *) malloc (strlen (layer->Name) + strlen (_("Layer %s Attributes"))); sprintf (buf, _("Layer %s Attributes"), layer->Name); gui->edit_attributes(buf, &(layer->Attributes)); free (buf); return 0; } case F_Element: { int n_found = 0; ElementType *e = NULL; ELEMENT_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, element)) { e = element; n_found ++; } } END_LOOP; if (n_found > 1) { Message (_("Too many elements selected\n")); return 1; } if (n_found == 0) { void *ptrtmp; gui->get_coords (_("Click on an element"), &x, &y); if ((SearchScreen (x, y, ELEMENT_TYPE, &ptrtmp, &ptrtmp, &ptrtmp)) != NO_TYPE) e = (ElementType *) ptrtmp; else { Message (_("No element found there\n")); return 1; } } if (NAMEONPCB_NAME(e)) { buf = (char *) malloc (strlen (NAMEONPCB_NAME(e)) + strlen (_("Element %s Attributes"))); sprintf(buf, _("Element %s Attributes"), NAMEONPCB_NAME(e)); } else { buf = strdup (_("Unnamed Element Attributes")); } gui->edit_attributes(buf, &(e->Attributes)); free (buf); break; } default: AFAIL (attributes); } return 0; } /* --------------------------------------------------------------------------- */ static const char setvialayers_syntax[] = N_("SetViaLayers(Object|SelectedVias|Selected[,ThroughHole|TH])\n" "SetViaLayers(Object|SelectedVias|Selected,from,to)\n" "SetViaLayers(Object|SelectedVias|Selected,[c|-|from],[c|-|to])" ); static const char setvialayers_help[] = N_("Sets starting and ending layer for burried/blind/standard vias."); /* %start-doc actions setvialayers Specifies layers, which are connected by via. @table @code @item TH|ThroughHole The vias will be set as through-hole, connecting all layers @item from layer name or layer number of the first layer to be connected by via; "-" stands for unchanged, "c" stands for currently selected layer @item to layer name or layer number of the last layer to be connected by via; "-" stands for unchanged, "c" stands for currently selected layer @end table If no parameter us used, dialog is displayed (if implemented in the respective GUI HID). %end-doc */ static bool identify_layer (char *layer_name, Cardinal *layer_no) { int layer; if (strcmp (layer_name, "-") == 0) { *layer_no = -1; return true; } if (strcmp (layer_name, "c") == 0) { if ((unsigned int)INDEXOFCURRENT < max_copper_layer) { *layer_no = INDEXOFCURRENT; return true; } } layer = SearchLayerByName (PCB->Data, layer_name); if (layer == -1) { if (sscanf (layer_name, "%d", &layer) != 1) layer = -1; } if (layer != -1) *layer_no = layer; return (layer != -1); } static int ActionSetViaLayers (int argc, char **argv, Coord x, Coord y) { char *function = ARG (0); char *layername_from = ARG (1); char *layername_to = ARG (2); Cardinal layer_from ; Cardinal layer_to = -1; if (!function) AFAIL (setvialayers); if ( /* !gui->edit_attributes &&*/ argc < 2) { Message (_("This GUI doesn't support Via Layers editing\n")); return 1; } if (GetFunctionID (layername_from) == F_ThroughHole) { layer_from = 0; layer_to = 0; } else { if (!identify_layer (layername_from, &layer_from) || !identify_layer (layername_to, &layer_to)) { Message (_("Sorry, wrong layers specified.\n")); return 1; } } /* ensure that layer_from < layer_to */ if (layer_from != -1 && layer_to != -1 && layer_from > layer_to) { int tmp; tmp = layer_from; layer_from = layer_to; layer_to = tmp; } if (layer_to != -1) layer_to = min (layer_to, max_copper_layer-1); switch (GetFunctionID (function)) { case F_Object: { int type; void *ptr1, *ptr2, *ptr3; if ((type = SearchScreen (Crosshair.X, Crosshair.Y, VIA_TYPE, &ptr1, &ptr2, &ptr3)) != NO_TYPE) { if (TEST_FLAG (LOCKFLAG, (PinType *) ptr1)) Message (_("Sorry, the object is locked\n")); else { if (ChangeObjectViaLayers (ptr1, ptr2, ptr3, layer_from, layer_to)) { SetChangedFlag (true); } } } break; case F_SelectedVias: case F_Selected: if (ChangeSelectedViaLayers (layer_from, layer_to)) { SetChangedFlag (true); } break; } } return 0; } /* --------------------------------------------------------------------------- */ HID_Action action_action_list[] = { {"AddRats", 0, ActionAddRats, addrats_help, addrats_syntax} , {"Attributes", 0, ActionAttributes, attributes_help, attributes_syntax} , {"Atomic", 0, ActionAtomic, atomic_help, atomic_syntax} , {"AutoPlaceSelected", 0, ActionAutoPlaceSelected, autoplace_help, autoplace_syntax} , {"AutoRoute", 0, ActionAutoRoute, autoroute_help, autoroute_syntax} , {"ChangeClearSize", 0, ActionChangeClearSize, changeclearsize_help, changeclearsize_syntax} , {"ChangeDrillSize", 0, ActionChange2ndSize, changedrillsize_help, changedrillsize_syntax} , {"ChangeHole", 0, ActionChangeHole, changehold_help, changehold_syntax} , {"ChangeJoin", 0, ActionChangeJoin, changejoin_help, changejoin_syntax} , {"ChangeName", 0, ActionChangeName, changename_help, changename_syntax} , {"ChangePaste", 0, ActionChangePaste, changepaste_help, changepaste_syntax} , {"ChangePinName", 0, ActionChangePinName, changepinname_help, changepinname_syntax} , {"ChangeSize", 0, ActionChangeSize, changesize_help, changesize_syntax} , {"ChangeSquare", 0, ActionChangeSquare, changesquare_help, changesquare_syntax} , {"ChangeOctagon", 0, ActionChangeOctagon, changeoctagon_help, changeoctagon_syntax} , {"ClearSquare", 0, ActionClearSquare, clearsquare_help, clearsquare_syntax} , {"ClearOctagon", 0, ActionClearOctagon, clearoctagon_help, clearoctagon_syntax} , {"Connection", 0, ActionConnection, connection_help, connection_syntax} , {"Delete", 0, ActionDelete, delete_help, delete_syntax} , {"DeleteRats", 0, ActionDeleteRats, deleterats_help, deleterats_syntax} , {"DisperseElements", 0, ActionDisperseElements, disperseelements_help, disperseelements_syntax} , {"Display", 0, ActionDisplay, display_help, display_syntax} , {"DumpLibrary", 0, ActionDumpLibrary, dumplibrary_help, dumplibrary_syntax} , {"ExecuteFile", 0, ActionExecuteFile, executefile_help, executefile_syntax} , {"Flip", N_("Click on Object or Flip Point"), ActionFlip, flip_help, flip_syntax} , {"LoadFrom", 0, ActionLoadFrom, loadfrom_help, loadfrom_syntax} , {"MarkCrosshair", 0, ActionMarkCrosshair, markcrosshair_help, markcrosshair_syntax} , {"Message", 0, ActionMessage, message_help, message_syntax} , {"MinMaskGap", 0, ActionMinMaskGap, minmaskgap_help, minmaskgap_syntax} , {"MinClearGap", 0, ActionMinClearGap, mincleargap_help, mincleargap_syntax} , {"Mode", 0, ActionMode, mode_help, mode_syntax} , {"MorphPolygon", 0, ActionMorphPolygon, morphpolygon_help, morphpolygon_syntax} , {"PasteBuffer", 0, ActionPasteBuffer, pastebuffer_help, pastebuffer_syntax} , {"Quit", 0, ActionQuit, quit_help, quit_syntax} , {"RemoveSelected", 0, ActionRemoveSelected, removeselected_help, removeselected_syntax} , {"Renumber", 0, ActionRenumber, renumber_help, renumber_syntax} , {"RipUp", 0, ActionRipUp, ripup_help, ripup_syntax} , {"Select", 0, ActionSelect, select_help, select_syntax} , {"Unselect", 0, ActionUnselect, unselect_help, unselect_syntax} , {"SaveSettings", 0, ActionSaveSettings, savesettings_help, savesettings_syntax} , {"SaveTo", 0, ActionSaveTo, saveto_help, saveto_syntax} , {"SetSquare", 0, ActionSetSquare, setsquare_help, setsquare_syntax} , {"SetOctagon", 0, ActionSetOctagon, setoctagon_help, setoctagon_syntax} , {"SetThermal", 0, ActionSetThermal, setthermal_help, setthermal_syntax} , {"SetValue", 0, ActionSetValue, setvalue_help, setvalue_syntax} , {"ToggleHideName", 0, ActionToggleHideName, togglehidename_help, togglehidename_syntax} , {"Undo", 0, ActionUndo, undo_help, undo_syntax} , {"Redo", 0, ActionRedo, redo_help, redo_syntax} , {"SetSame", N_("Select item to use attributes from"), ActionSetSame, setsame_help, setsame_syntax} , {"SetFlag", 0, ActionSetFlag, setflag_help, setflag_syntax} , {"ClrFlag", 0, ActionClrFlag, clrflag_help, clrflag_syntax} , {"ChangeFlag", 0, ActionChangeFlag, changeflag_help, changeflag_syntax} , {"Polygon", 0, ActionPolygon, polygon_help, polygon_syntax} , {"RouteStyle", 0, ActionRouteStyle, routestyle_help, routestyle_syntax} , {"MoveObject", N_("Select an Object"), ActionMoveObject, moveobject_help, moveobject_syntax} , {"MoveToCurrentLayer", 0, ActionMoveToCurrentLayer, movetocurrentlayer_help, movetocurrentlayer_syntax} , {"New", 0, ActionNew, new_help, new_syntax} , {"pscalib", 0, ActionPSCalib} , {"ElementList", 0, ActionElementList, elementlist_help, elementlist_syntax} , {"ElementSetAttr", 0, ActionElementSetAttr, elementsetattr_help, elementsetattr_syntax} , {"ExecCommand", 0, ActionExecCommand, execcommand_help, execcommand_syntax} , {"ImportTinyCAD", 0, ActionImportTinyCAD, tcad_import_help, tcad_import_syntax} , {"Import", 0, ActionImport, import_help, import_syntax} , {"SetViaLayers", 0, ActionSetViaLayers, setvialayers_help, setvialayers_syntax} , }; REGISTER_ACTIONS (action_action_list) pcb-4.2.2/src/clip.h0000664000076400007640000000263113434555140011113 00000000000000/*! * \file src/clip.h * * \brief Prototypes for inserting points into objects. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 2004 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_CLIP_H #define PCB_CLIP_H #include "global.h" /* --------------------------------------------------------------------------- * prototypes */ bool ClipLine (double minx, double miny, double maxx, double maxy, double *x1, double *y1, double *x2, double *y2, double margin); #endif pcb-4.2.2/src/line.h0000664000076400007640000000261113434555140011111 00000000000000/*! * \file src/line.h * * \brief Prototypes for inserting points into objects. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 2004 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_LINE_H #define PCB_LINE_H #include "global.h" /* --------------------------------------------------------------------------- * prototypes */ void AdjustAttachedLine (void); void AdjustTwoLine (bool); void FortyFiveLine (AttachedLineType *); void EnforceLineDRC (void); #endif pcb-4.2.2/src/main-test.c0000664000076400007640000000250413533277055012065 00000000000000/*! * \file src/main-test.c * * \brief . * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2015 Andrew Poelstra * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Andrew Poelstra, 16966 60A Ave, V3S 8X5 Surrey, BC, Canada * asp11@sfu.ca */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include "pcb-printf.h" #include "object_list.h" int main (int argc, char *argv[]) { initialize_units (); pcb_printf_register_tests (); object_list_register_tests (); g_test_init (&argc, &argv, NULL); g_test_run (); return 0; } pcb-4.2.2/src/gpcb-menu.res.h0000664000076400007640000006562713611113563012643 00000000000000# 234 "gpcb-menu.res" char *s = N_(" Center"); # 236 "gpcb-menu.res" char *s = N_(" Crosshair"); # 235 "gpcb-menu.res" char *s = N_(" Mark"); # 74 "gpcb-menu.res" char *s = N_(" a single element"); # 75 "gpcb-menu.res" char *s = N_(" all elements"); # 76 "gpcb-menu.res" char *s = N_(" unused pins"); # 211 "gpcb-menu.res" char *s = N_("'All-direction' lines"); # 211 "gpcb-menu.res" char *s = N_("."); # 454 "gpcb-menu.res" char *s = N_("/"); # 150 "gpcb-menu.res" char *s = N_("0.01 mm"); # 151 "gpcb-menu.res" char *s = N_("0.05 mm"); # 142 "gpcb-menu.res" char *s = N_("0.1 mil"); # 152 "gpcb-menu.res" char *s = N_("0.1 mm"); # 153 "gpcb-menu.res" char *s = N_("0.25 mm"); # 154 "gpcb-menu.res" char *s = N_("0.5 mm"); # 143 "gpcb-menu.res" char *s = N_("1 mil"); # 155 "gpcb-menu.res" char *s = N_("1 mm"); # 145 "gpcb-menu.res" char *s = N_("10 mil"); # 148 "gpcb-menu.res" char *s = N_("100 mil"); # 146 "gpcb-menu.res" char *s = N_("25 mil"); # 144 "gpcb-menu.res" char *s = N_("5 mil"); # 147 "gpcb-menu.res" char *s = N_("50 mil"); # 480 "gpcb-menu.res" char *s = N_(":"); # 211 "gpcb-menu.res" char *s = N_("."); # 454 "gpcb-menu.res" char *s = N_("/"); # 480 "gpcb-menu.res" char *s = N_(":"); # 363 "gpcb-menu.res" char *s = N_("="); # 395 "gpcb-menu.res" char *s = N_("BackSpace"); # 389 "gpcb-menu.res" char *s = N_("Delete"); # 460 "gpcb-menu.res" char *s = N_("Down"); # 467 "gpcb-menu.res" char *s = N_("Enter"); # 537 "gpcb-menu.res" char *s = N_("Escape"); # 521 "gpcb-menu.res" char *s = N_("F1"); # 531 "gpcb-menu.res" char *s = N_("F10"); # 532 "gpcb-menu.res" char *s = N_("F11"); # 536 "gpcb-menu.res" char *s = N_("F12"); # 522 "gpcb-menu.res" char *s = N_("F2"); # 523 "gpcb-menu.res" char *s = N_("F3"); # 524 "gpcb-menu.res" char *s = N_("F4"); # 525 "gpcb-menu.res" char *s = N_("F5"); # 526 "gpcb-menu.res" char *s = N_("F6"); # 528 "gpcb-menu.res" char *s = N_("F7"); # 529 "gpcb-menu.res" char *s = N_("F8"); # 530 "gpcb-menu.res" char *s = N_("F9"); # 533 "gpcb-menu.res" char *s = N_("Insert"); # 461 "gpcb-menu.res" char *s = N_("Left"); # 462 "gpcb-menu.res" char *s = N_("Right"); # 185 "gpcb-menu.res" char *s = N_("Tab"); # 459 "gpcb-menu.res" char *s = N_("Up"); # 456 "gpcb-menu.res" char *s = N_("["); # 457 "gpcb-menu.res" char *s = N_("]"); # 415 "gpcb-menu.res" char *s = N_("a"); # 416 "gpcb-menu.res" char *s = N_("b"); # 189 "gpcb-menu.res" char *s = N_("c"); # 168 "gpcb-menu.res" char *s = N_("d"); # 348 "gpcb-menu.res" char *s = N_("e"); # 417 "gpcb-menu.res" char *s = N_("f"); # 158 "gpcb-menu.res" char *s = N_("g"); # 418 "gpcb-menu.res" char *s = N_("h"); # 476 "gpcb-menu.res" char *s = N_("i"); # 421 "gpcb-menu.res" char *s = N_("j"); # 423 "gpcb-menu.res" char *s = N_("k"); # 427 "gpcb-menu.res" char *s = N_("l"); # 429 "gpcb-menu.res" char *s = N_("m"); # 108 "gpcb-menu.res" char *s = N_("n"); # 347 "gpcb-menu.res" char *s = N_("o"); # 439 "gpcb-menu.res" char *s = N_("p"); # 441 "gpcb-menu.res" char *s = N_("q"); # 387 "gpcb-menu.res" char *s = N_("r"); # 442 "gpcb-menu.res" char *s = N_("s"); # 455 "gpcb-menu.res" char *s = N_("space"); # 446 "gpcb-menu.res" char *s = N_("t"); # 92 "gpcb-menu.res" char *s = N_("u"); # 173 "gpcb-menu.res" char *s = N_("v"); # 453 "gpcb-menu.res" char *s = N_("w"); # 365 "gpcb-menu.res" char *s = N_("y"); # 170 "gpcb-menu.res" char *s = N_("z"); # 227 "gpcb-menu.res" char *s = N_("|"); # 363 "gpcb-menu.res" char *s = N_("="); # 415 "gpcb-menu.res" char *s = N_("A"); # 483 "gpcb-menu.res" char *s = N_("About..."); # 453 "gpcb-menu.res" char *s = N_("Add All Rats"); # 201 "gpcb-menu.res" char *s = N_("Add new layer"); # 452 "gpcb-menu.res" char *s = N_("AddRats Selected"); # 432 "gpcb-menu.res" char *s = N_("AddRats to selected pins"); # 369 "gpcb-menu.res" char *s = N_("All"); # 256 "gpcb-menu.res" char *s = N_("All objects"); # 274 "gpcb-menu.res" char *s = N_("Alt-R"); # 274 "gpcb-menu.res" char *s = N_("Altr"); # 377 "gpcb-menu.res" char *s = N_("Apply vendor drill mapping"); # 320 "gpcb-menu.res" char *s = N_("Arbitrarily Rotate Buffer"); # 523 "gpcb-menu.res" char *s = N_("Arc"); # 532 "gpcb-menu.res" char *s = N_("Arrow"); # 455 "gpcb-menu.res" char *s = N_("Arrow Mode"); # 230 "gpcb-menu.res" char *s = N_("Auto buried vias"); # 216 "gpcb-menu.res" char *s = N_("Auto enforce DRC clearance"); # 508 "gpcb-menu.res" char *s = N_("Auto place selected elements"); # 212 "gpcb-menu.res" char *s = N_("Auto swap line start angle"); # 357 "gpcb-menu.res" char *s = N_("Auto-Optimize"); # 264 "gpcb-menu.res" char *s = N_("Auto-place selected elements"); # 352 "gpcb-menu.res" char *s = N_("Auto-route all rats"); # 351 "gpcb-menu.res" char *s = N_("Auto-route selected rats"); # 223 "gpcb-menu.res" char *s = N_("Auto-zero delta measurements"); # 509 "gpcb-menu.res" char *s = N_("Autoroute selected elements"); # 416 "gpcb-menu.res" char *s = N_("B"); # 395 "gpcb-menu.res" char *s = N_("Backspace"); # 327 "gpcb-menu.res" char *s = N_("Break buffer elements to pieces"); # 528 "gpcb-menu.res" char *s = N_("Buffer"); # 125 "gpcb-menu.res" char *s = N_("Buried from"); # 304 "gpcb-menu.res" char *s = N_("Buried from current layer"); # 126 "gpcb-menu.res" char *s = N_("Buried to"); # 305 "gpcb-menu.res" char *s = N_("Buried to current layer"); # 189 "gpcb-menu.res" char *s = N_("C"); # 80 "gpcb-menu.res" char *s = N_("Calibrate Printer..."); # 537 "gpcb-menu.res" char *s = N_("Cancel"); # 189 "gpcb-menu.res" char *s = N_("Center cursor"); # 290 "gpcb-menu.res" char *s = N_("Change drilling hole of selected objects"); # 277 "gpcb-menu.res" char *s = N_("Change size of selected objects"); # 297 "gpcb-menu.res" char *s = N_("Change square-flag of selected objects"); # 302 "gpcb-menu.res" char *s = N_("Change type of selected vias"); # 444 "gpcb-menu.res" char *s = N_("ChangeDrill +5 mil"); # 445 "gpcb-menu.res" char *s = N_("ChangeDrill -5 mil"); # 420 "gpcb-menu.res" char *s = N_("ChangeHole Object"); # 421 "gpcb-menu.res" char *s = N_("ChangeJoin Object"); # 422 "gpcb-menu.res" char *s = N_("ChangeJoin SelectedObject"); # 438 "gpcb-menu.res" char *s = N_("ChangeOctagon Object"); # 442 "gpcb-menu.res" char *s = N_("ChangeSize +"); # 443 "gpcb-menu.res" char *s = N_("ChangeSize -"); # 441 "gpcb-menu.res" char *s = N_("ChangeSquare Object"); # 229 "gpcb-menu.res" char *s = N_("Check polygons"); # 423 "gpcb-menu.res" char *s = N_("Clear Object +"); # 424 "gpcb-menu.res" char *s = N_("Clear Object -"); # 425 "gpcb-menu.res" char *s = N_("Clear Selected +"); # 426 "gpcb-menu.res" char *s = N_("Clear Selected -"); # 325 "gpcb-menu.res" char *s = N_("Clear buffer"); # 94 "gpcb-menu.res" char *s = N_("Clear undo-buffer"); # 467 "gpcb-menu.res" char *s = N_("Click"); # 480 "gpcb-menu.res" char *s = N_("Command Entry"); # 340 "gpcb-menu.res" char *s = N_("Connects"); # 326 "gpcb-menu.res" char *s = N_("Convert buffer to element"); # 507 "gpcb-menu.res" char *s = N_("Convert selection to element"); # 535 "gpcb-menu.res" char *s = N_("Copy"); # 494 "gpcb-menu.res" char *s = N_("Copy selection to buffer"); # 99 "gpcb-menu.res" char *s = N_("Copy to buffer"); # 215 "gpcb-menu.res" char *s = N_("Crosshair shows DRC clearance"); # 214 "gpcb-menu.res" char *s = N_("Crosshair snaps to pins and pads"); # 188 "gpcb-menu.res" char *s = N_("Ctrl ShiftTab"); # 445 "gpcb-menu.res" char *s = N_("Ctrl Shiftd"); # 125 "gpcb-menu.res" char *s = N_("Ctrl Shiftf"); # 451 "gpcb-menu.res" char *s = N_("Ctrl Shiftl"); # 228 "gpcb-menu.res" char *s = N_("Ctrl Shiftp"); # 126 "gpcb-menu.res" char *s = N_("Ctrl Shiftt"); # 105 "gpcb-menu.res" char *s = N_("Ctrl-A"); # 101 "gpcb-menu.res" char *s = N_("Ctrl-C"); # 444 "gpcb-menu.res" char *s = N_("Ctrl-D"); # 341 "gpcb-menu.res" char *s = N_("Ctrl-F"); # 420 "gpcb-menu.res" char *s = N_("Ctrl-H"); # 425 "gpcb-menu.res" char *s = N_("Ctrl-K"); # 450 "gpcb-menu.res" char *s = N_("Ctrl-L"); # 430 "gpcb-menu.res" char *s = N_("Ctrl-M"); # 57 "gpcb-menu.res" char *s = N_("Ctrl-N"); # 438 "gpcb-menu.res" char *s = N_("Ctrl-O"); # 264 "gpcb-menu.res" char *s = N_("Ctrl-P"); # 85 "gpcb-menu.res" char *s = N_("Ctrl-Q"); # 384 "gpcb-menu.res" char *s = N_("Ctrl-R"); # 60 "gpcb-menu.res" char *s = N_("Ctrl-S"); # 445 "gpcb-menu.res" char *s = N_("Ctrl-Shift-D"); # 451 "gpcb-menu.res" char *s = N_("Ctrl-Shift-L"); # 228 "gpcb-menu.res" char *s = N_("Ctrl-Shift-P"); # 188 "gpcb-menu.res" char *s = N_("Ctrl-Shift-Tab"); # 187 "gpcb-menu.res" char *s = N_("Ctrl-Tab"); # 102 "gpcb-menu.res" char *s = N_("Ctrl-V"); # 98 "gpcb-menu.res" char *s = N_("Ctrl-X"); # 187 "gpcb-menu.res" char *s = N_("CtrlTab"); # 105 "gpcb-menu.res" char *s = N_("Ctrla"); # 101 "gpcb-menu.res" char *s = N_("Ctrlc"); # 444 "gpcb-menu.res" char *s = N_("Ctrld"); # 341 "gpcb-menu.res" char *s = N_("Ctrlf"); # 420 "gpcb-menu.res" char *s = N_("Ctrlh"); # 425 "gpcb-menu.res" char *s = N_("Ctrlk"); # 450 "gpcb-menu.res" char *s = N_("Ctrll"); # 430 "gpcb-menu.res" char *s = N_("Ctrlm"); # 57 "gpcb-menu.res" char *s = N_("Ctrln"); # 438 "gpcb-menu.res" char *s = N_("Ctrlo"); # 264 "gpcb-menu.res" char *s = N_("Ctrlp"); # 85 "gpcb-menu.res" char *s = N_("Ctrlq"); # 384 "gpcb-menu.res" char *s = N_("Ctrlr"); # 60 "gpcb-menu.res" char *s = N_("Ctrls"); # 102 "gpcb-menu.res" char *s = N_("Ctrlv"); # 98 "gpcb-menu.res" char *s = N_("Ctrlx"); # 197 "gpcb-menu.res" char *s = N_("Current Layer"); # 114 "gpcb-menu.res" char *s = N_("CurrentLayer"); # 500 "gpcb-menu.res" char *s = N_("Cut selection to buffer"); # 313 "gpcb-menu.res" char *s = N_("Cut to buffer"); # 454 "gpcb-menu.res" char *s = N_("Cycle Clip"); # 168 "gpcb-menu.res" char *s = N_("D"); # 478 "gpcb-menu.res" char *s = N_("DRC Check"); # 358 "gpcb-menu.res" char *s = N_("Debumpify"); # 389 "gpcb-menu.res" char *s = N_("Delete"); # 200 "gpcb-menu.res" char *s = N_("Delete current layer"); # 163 "gpcb-menu.res" char *s = N_("Description"); # 375 "gpcb-menu.res" char *s = N_("Design Rule Checker"); # 265 "gpcb-menu.res" char *s = N_("Disperse all elements"); # 266 "gpcb-menu.res" char *s = N_("Disperse selected elements"); # 162 "gpcb-menu.res" char *s = N_("Displayed element name"); # 464 "gpcb-menu.res" char *s = N_("Down"); # 348 "gpcb-menu.res" char *s = N_("E"); # 91 "gpcb-menu.res" char *s = N_("Edit"); # 195 "gpcb-menu.res" char *s = N_("Edit Layer Groups"); # 112 "gpcb-menu.res" char *s = N_("Edit attributes of"); # 107 "gpcb-menu.res" char *s = N_("Edit name of"); # 120 "gpcb-menu.res" char *s = N_("Edit..."); # 115 "gpcb-menu.res" char *s = N_("Element"); # 298 "gpcb-menu.res" char *s = N_("Elements"); # 167 "gpcb-menu.res" char *s = N_("Enable Pinout shows number"); # 134 "gpcb-menu.res" char *s = N_("Enable visible grid"); # 467 "gpcb-menu.res" char *s = N_("Enter"); # 348 "gpcb-menu.res" char *s = N_("Erase rats nest"); # 349 "gpcb-menu.res" char *s = N_("Erase selected rats"); # 537 "gpcb-menu.res" char *s = N_("Esc"); # 78 "gpcb-menu.res" char *s = N_("Export..."); # 417 "gpcb-menu.res" char *s = N_("F"); # 521 "gpcb-menu.res" char *s = N_("F1"); # 531 "gpcb-menu.res" char *s = N_("F10"); # 532 "gpcb-menu.res" char *s = N_("F11"); # 536 "gpcb-menu.res" char *s = N_("F12"); # 522 "gpcb-menu.res" char *s = N_("F2"); # 523 "gpcb-menu.res" char *s = N_("F3"); # 524 "gpcb-menu.res" char *s = N_("F4"); # 525 "gpcb-menu.res" char *s = N_("F5"); # 526 "gpcb-menu.res" char *s = N_("F6"); # 528 "gpcb-menu.res" char *s = N_("F7"); # 529 "gpcb-menu.res" char *s = N_("F8"); # 530 "gpcb-menu.res" char *s = N_("F9"); # 56 "gpcb-menu.res" char *s = N_("File"); # 417 "gpcb-menu.res" char *s = N_("Find Connections"); # 416 "gpcb-menu.res" char *s = N_("Flip Object"); # 186 "gpcb-menu.res" char *s = N_("Flip left/right"); # 185 "gpcb-menu.res" char *s = N_("Flip up/down"); # 368 "gpcb-menu.res" char *s = N_("Found"); # 158 "gpcb-menu.res" char *s = N_("G"); # 385 "gpcb-menu.res" char *s = N_("Generate drill summary"); # 513 "gpcb-menu.res" char *s = N_("Generate object report"); # 366 "gpcb-menu.res" char *s = N_("Global Puller"); # 158 "gpcb-menu.res" char *s = N_("Grid +"); # 157 "gpcb-menu.res" char *s = N_("Grid -"); # 139 "gpcb-menu.res" char *s = N_("Grid size"); # 135 "gpcb-menu.res" char *s = N_("Grid units"); # 418 "gpcb-menu.res" char *s = N_("H"); # 219 "gpcb-menu.res" char *s = N_("Hide Names"); # 233 "gpcb-menu.res" char *s = N_("Import New Elements at"); # 64 "gpcb-menu.res" char *s = N_("Import Schematics"); # 383 "gpcb-menu.res" char *s = N_("Info"); # 533 "gpcb-menu.res" char *s = N_("Insert"); # 533 "gpcb-menu.res" char *s = N_("Insert Point"); # 421 "gpcb-menu.res" char *s = N_("J"); # 423 "gpcb-menu.res" char *s = N_("K"); # 388 "gpcb-menu.res" char *s = N_("Key Bindings"); # 427 "gpcb-menu.res" char *s = N_("L"); # 113 "gpcb-menu.res" char *s = N_("Layout"); # 465 "gpcb-menu.res" char *s = N_("Left"); # 476 "gpcb-menu.res" char *s = N_("Library"); # 522 "gpcb-menu.res" char *s = N_("Line"); # 427 "gpcb-menu.res" char *s = N_("Line Tool size +"); # 428 "gpcb-menu.res" char *s = N_("Line Tool size -"); # 279 "gpcb-menu.res" char *s = N_("Lines +10 mil"); # 278 "gpcb-menu.res" char *s = N_("Lines -10 mil"); # 58 "gpcb-menu.res" char *s = N_("Load a layout from a file"); # 68 "gpcb-menu.res" char *s = N_("Load element to buffer"); # 69 "gpcb-menu.res" char *s = N_("Load layout to buffer"); # 70 "gpcb-menu.res" char *s = N_("Load netlist"); # 71 "gpcb-menu.res" char *s = N_("Load vendor resource file"); # 536 "gpcb-menu.res" char *s = N_("Lock"); # 217 "gpcb-menu.res" char *s = N_("Lock Names"); # 341 "gpcb-menu.res" char *s = N_("Lookup connection"); # 429 "gpcb-menu.res" char *s = N_("M"); # 430 "gpcb-menu.res" char *s = N_("MarkCrosshair"); # 477 "gpcb-menu.res" char *s = N_("Message Log"); # 322 "gpcb-menu.res" char *s = N_("Mirror buffer (left/right)"); # 321 "gpcb-menu.res" char *s = N_("Mirror buffer (up/down)"); # 364 "gpcb-menu.res" char *s = N_("Miter"); # 172 "gpcb-menu.res" char *s = N_("More zooms and view changes"); # 534 "gpcb-menu.res" char *s = N_("Move"); # 429 "gpcb-menu.res" char *s = N_("Move Object to current layer"); # 203 "gpcb-menu.res" char *s = N_("Move current layer down"); # 202 "gpcb-menu.res" char *s = N_("Move current layer up"); # 268 "gpcb-menu.res" char *s = N_("Move selected elements to other side"); # 269 "gpcb-menu.res" char *s = N_("Move selected to current layer"); # 108 "gpcb-menu.res" char *s = N_("N"); # 479 "gpcb-menu.res" char *s = N_("Netlist"); # 57 "gpcb-menu.res" char *s = N_("New"); # 224 "gpcb-menu.res" char *s = N_("New lines, arcs clear polygons"); # 225 "gpcb-menu.res" char *s = N_("New polygons are full ones"); # 140 "gpcb-menu.res" char *s = N_("No Grid"); # 520 "gpcb-menu.res" char *s = N_("None"); # 347 "gpcb-menu.res" char *s = N_("O"); # 218 "gpcb-menu.res" char *s = N_("Only Names"); # 372 "gpcb-menu.res" char *s = N_("Only autorouted nets"); # 58 "gpcb-menu.res" char *s = N_("Open..."); # 491 "gpcb-menu.res" char *s = N_("Operations on selections"); # 512 "gpcb-menu.res" char *s = N_("Operations on this location"); # 346 "gpcb-menu.res" char *s = N_("Optimize rats nest"); # 356 "gpcb-menu.res" char *s = N_("Optimize routed tracks"); # 273 "gpcb-menu.res" char *s = N_("Optimize selected rats"); # 362 "gpcb-menu.res" char *s = N_("Ortho pull"); # 213 "gpcb-menu.res" char *s = N_("Orthogonal moves"); # 439 "gpcb-menu.res" char *s = N_("P"); # 258 "gpcb-menu.res" char *s = N_("Pads"); # 281 "gpcb-menu.res" char *s = N_("Pads +10 mil"); # 280 "gpcb-menu.res" char *s = N_("Pads -10 mil"); # 315 "gpcb-menu.res" char *s = N_("Paste buffer"); # 481 "gpcb-menu.res" char *s = N_("Pinout"); # 299 "gpcb-menu.res" char *s = N_("Pins"); # 294 "gpcb-menu.res" char *s = N_("Pins +10 mil"); # 293 "gpcb-menu.res" char *s = N_("Pins -10 mil"); # 168 "gpcb-menu.res" char *s = N_("Pins/Via show Name/Number"); # 526 "gpcb-menu.res" char *s = N_("Polygon"); # 440 "gpcb-menu.res" char *s = N_("Polygon Close"); # 527 "gpcb-menu.res" char *s = N_("Polygon Hole"); # 439 "gpcb-menu.res" char *s = N_("Polygon PreviousPoint"); # 83 "gpcb-menu.res" char *s = N_("Preferences..."); # 81 "gpcb-menu.res" char *s = N_("Print..."); # 365 "gpcb-menu.res" char *s = N_("Puller"); # 441 "gpcb-menu.res" char *s = N_("Q"); # 85 "gpcb-menu.res" char *s = N_("Quit"); # 387 "gpcb-menu.res" char *s = N_("R"); # 160 "gpcb-menu.res" char *s = N_("Realign grid"); # 525 "gpcb-menu.res" char *s = N_("Rectangle"); # 93 "gpcb-menu.res" char *s = N_("Redo"); # 517 "gpcb-menu.res" char *s = N_("Redo last undone operation"); # 164 "gpcb-menu.res" char *s = N_("Reference Designator"); # 529 "gpcb-menu.res" char *s = N_("Remove"); # 398 "gpcb-menu.res" char *s = N_("Remove Connected"); # 395 "gpcb-menu.res" char *s = N_("Remove Selected"); # 493 "gpcb-menu.res" char *s = N_("Remove selected objects"); # 386 "gpcb-menu.res" char *s = N_("Report found pins/pads"); # 387 "gpcb-menu.res" char *s = N_("Report net length"); # 222 "gpcb-menu.res" char *s = N_("Require unique element names"); # 344 "gpcb-menu.res" char *s = N_("Reset all connections"); # 343 "gpcb-menu.res" char *s = N_("Reset scanned lines/polygons"); # 342 "gpcb-menu.res" char *s = N_("Reset scanned pads/pins/vias"); # 62 "gpcb-menu.res" char *s = N_("Revert"); # 62 "gpcb-menu.res" char *s = N_("Revert to the layout stored on disk"); # 466 "gpcb-menu.res" char *s = N_("Right"); # 354 "gpcb-menu.res" char *s = N_("Rip up all auto-routed tracks"); # 510 "gpcb-menu.res" char *s = N_("Rip up selected auto-routed tracks"); # 530 "gpcb-menu.res" char *s = N_("Rotate"); # 317 "gpcb-menu.res" char *s = N_("Rotate buffer 90 deg CCW"); # 319 "gpcb-menu.res" char *s = N_("Rotate buffer 90 deg CW"); # 118 "gpcb-menu.res" char *s = N_("Route Styles"); # 221 "gpcb-menu.res" char *s = N_("Rubber band mode"); # 442 "gpcb-menu.res" char *s = N_("S"); # 60 "gpcb-menu.res" char *s = N_("Save"); # 61 "gpcb-menu.res" char *s = N_("Save As..."); # 328 "gpcb-menu.res" char *s = N_("Save buffer elements to file"); # 73 "gpcb-menu.res" char *s = N_("Save connection data of"); # 60 "gpcb-menu.res" char *s = N_("Saves current layout"); # 61 "gpcb-menu.res" char *s = N_("Saves current layout into a new file"); # 245 "gpcb-menu.res" char *s = N_("Select"); # 330 "gpcb-menu.res" char *s = N_("Select Buffer #1"); # 331 "gpcb-menu.res" char *s = N_("Select Buffer #2"); # 332 "gpcb-menu.res" char *s = N_("Select Buffer #3"); # 333 "gpcb-menu.res" char *s = N_("Select Buffer #4"); # 334 "gpcb-menu.res" char *s = N_("Select Buffer #5"); # 249 "gpcb-menu.res" char *s = N_("Select all buried vias"); # 248 "gpcb-menu.res" char *s = N_("Select all connected"); # 247 "gpcb-menu.res" char *s = N_("Select all found"); # 246 "gpcb-menu.res" char *s = N_("Select all visible"); # 255 "gpcb-menu.res" char *s = N_("Select by name"); # 431 "gpcb-menu.res" char *s = N_("Select shortest rat"); # 367 "gpcb-menu.res" char *s = N_("Selected"); # 238 "gpcb-menu.res" char *s = N_("Set Dispersion"); # 415 "gpcb-menu.res" char *s = N_("Set Same"); # 210 "gpcb-menu.res" char *s = N_("Settings"); # 61 "gpcb-menu.res" char *s = N_("Shift Ctrl-S"); # 104 "gpcb-menu.res" char *s = N_("Shift Ctrla"); # 426 "gpcb-menu.res" char *s = N_("Shift Ctrlk"); # 61 "gpcb-menu.res" char *s = N_("Shift Ctrls"); # 94 "gpcb-menu.res" char *s = N_("Shift Ctrlu"); # 449 "gpcb-menu.res" char *s = N_("Shift Ctrlv"); # 330 "gpcb-menu.res" char *s = N_("Shift-1"); # 331 "gpcb-menu.res" char *s = N_("Shift-2"); # 332 "gpcb-menu.res" char *s = N_("Shift-3"); # 333 "gpcb-menu.res" char *s = N_("Shift-4"); # 334 "gpcb-menu.res" char *s = N_("Shift-5"); # 357 "gpcb-menu.res" char *s = N_("Shift-="); # 268 "gpcb-menu.res" char *s = N_("Shift-B"); # 398 "gpcb-menu.res" char *s = N_("Shift-Backspace"); # 104 "gpcb-menu.res" char *s = N_("Shift-Ctrl-A"); # 426 "gpcb-menu.res" char *s = N_("Shift-Ctrl-K"); # 94 "gpcb-menu.res" char *s = N_("Shift-Ctrl-U"); # 449 "gpcb-menu.res" char *s = N_("Shift-Ctrl-V"); # 481 "gpcb-menu.res" char *s = N_("Shift-D"); # 270 "gpcb-menu.res" char *s = N_("Shift-Delete"); # 349 "gpcb-menu.res" char *s = N_("Shift-E"); # 344 "gpcb-menu.res" char *s = N_("Shift-F"); # 318 "gpcb-menu.res" char *s = N_("Shift-F7"); # 157 "gpcb-menu.res" char *s = N_("Shift-G"); # 419 "gpcb-menu.res" char *s = N_("Shift-H"); # 422 "gpcb-menu.res" char *s = N_("Shift-J"); # 424 "gpcb-menu.res" char *s = N_("Shift-K"); # 428 "gpcb-menu.res" char *s = N_("Shift-L"); # 269 "gpcb-menu.res" char *s = N_("Shift-M"); # 431 "gpcb-menu.res" char *s = N_("Shift-N"); # 432 "gpcb-menu.res" char *s = N_("Shift-O"); # 440 "gpcb-menu.res" char *s = N_("Shift-P"); # 93 "gpcb-menu.res" char *s = N_("Shift-R"); # 443 "gpcb-menu.res" char *s = N_("Shift-S"); # 447 "gpcb-menu.res" char *s = N_("Shift-T"); # 186 "gpcb-menu.res" char *s = N_("Shift-Tab"); # 448 "gpcb-menu.res" char *s = N_("Shift-V"); # 452 "gpcb-menu.res" char *s = N_("Shift-W"); # 171 "gpcb-menu.res" char *s = N_("Shift-Z"); # 330 "gpcb-menu.res" char *s = N_("Shift1"); # 331 "gpcb-menu.res" char *s = N_("Shift2"); # 332 "gpcb-menu.res" char *s = N_("Shift3"); # 333 "gpcb-menu.res" char *s = N_("Shift4"); # 334 "gpcb-menu.res" char *s = N_("Shift5"); # 357 "gpcb-menu.res" char *s = N_("Shift="); # 398 "gpcb-menu.res" char *s = N_("ShiftBackSpace"); # 270 "gpcb-menu.res" char *s = N_("ShiftDelete"); # 464 "gpcb-menu.res" char *s = N_("ShiftDown"); # 318 "gpcb-menu.res" char *s = N_("ShiftF7"); # 465 "gpcb-menu.res" char *s = N_("ShiftLeft"); # 466 "gpcb-menu.res" char *s = N_("ShiftRight"); # 186 "gpcb-menu.res" char *s = N_("ShiftTab"); # 463 "gpcb-menu.res" char *s = N_("ShiftUp"); # 268 "gpcb-menu.res" char *s = N_("Shiftb"); # 481 "gpcb-menu.res" char *s = N_("Shiftd"); # 349 "gpcb-menu.res" char *s = N_("Shifte"); # 344 "gpcb-menu.res" char *s = N_("Shiftf"); # 157 "gpcb-menu.res" char *s = N_("Shiftg"); # 419 "gpcb-menu.res" char *s = N_("Shifth"); # 422 "gpcb-menu.res" char *s = N_("Shiftj"); # 424 "gpcb-menu.res" char *s = N_("Shiftk"); # 428 "gpcb-menu.res" char *s = N_("Shiftl"); # 269 "gpcb-menu.res" char *s = N_("Shiftm"); # 431 "gpcb-menu.res" char *s = N_("Shiftn"); # 432 "gpcb-menu.res" char *s = N_("Shifto"); # 440 "gpcb-menu.res" char *s = N_("Shiftp"); # 93 "gpcb-menu.res" char *s = N_("Shiftr"); # 443 "gpcb-menu.res" char *s = N_("Shifts"); # 447 "gpcb-menu.res" char *s = N_("Shiftt"); # 448 "gpcb-menu.res" char *s = N_("Shiftv"); # 452 "gpcb-menu.res" char *s = N_("Shiftw"); # 171 "gpcb-menu.res" char *s = N_("Shiftz"); # 226 "gpcb-menu.res" char *s = N_("Show autorouter trials"); # 192 "gpcb-menu.res" char *s = N_("Shown Layers"); # 363 "gpcb-menu.res" char *s = N_("Simple optimization"); # 455 "gpcb-menu.res" char *s = N_("Space"); # 187 "gpcb-menu.res" char *s = N_("Spin 180 degrees"); # 464 "gpcb-menu.res" char *s = N_("Step +Down"); # 465 "gpcb-menu.res" char *s = N_("Step +Left"); # 466 "gpcb-menu.res" char *s = N_("Step +Right"); # 463 "gpcb-menu.res" char *s = N_("Step +Up"); # 460 "gpcb-menu.res" char *s = N_("Step Down"); # 461 "gpcb-menu.res" char *s = N_("Step Left"); # 462 "gpcb-menu.res" char *s = N_("Step Right"); # 459 "gpcb-menu.res" char *s = N_("Step Up"); # 188 "gpcb-menu.res" char *s = N_("Swap Sides"); # 446 "gpcb-menu.res" char *s = N_("T"); # 185 "gpcb-menu.res" char *s = N_("Tab"); # 457 "gpcb-menu.res" char *s = N_("Temp Arrow OFF"); # 456 "gpcb-menu.res" char *s = N_("Temp Arrow ON"); # 524 "gpcb-menu.res" char *s = N_("Text"); # 446 "gpcb-menu.res" char *s = N_("Text Tool scale +10 mil"); # 447 "gpcb-menu.res" char *s = N_("Text Tool scale -10 mil"); # 285 "gpcb-menu.res" char *s = N_("Texts +10 mil"); # 284 "gpcb-menu.res" char *s = N_("Texts -10 mil"); # 531 "gpcb-menu.res" char *s = N_("Thermal"); # 227 "gpcb-menu.res" char *s = N_("Thin draw"); # 228 "gpcb-menu.res" char *s = N_("Thin draw poly"); # 303 "gpcb-menu.res" char *s = N_("Through-hole"); # 66 "gpcb-menu.res" char *s = N_("TinyCAD"); # 418 "gpcb-menu.res" char *s = N_("ToggleHideName Object"); # 419 "gpcb-menu.res" char *s = N_("ToggleHideName SelectedElement"); # 353 "gpcb-menu.res" char *s = N_("Toporouter"); # 92 "gpcb-menu.res" char *s = N_("U"); # 92 "gpcb-menu.res" char *s = N_("Undo"); # 516 "gpcb-menu.res" char *s = N_("Undo last operation"); # 359 "gpcb-menu.res" char *s = N_("Unjaggy"); # 251 "gpcb-menu.res" char *s = N_("Unselect all"); # 253 "gpcb-menu.res" char *s = N_("Unselect all connected"); # 252 "gpcb-menu.res" char *s = N_("Unselect all found"); # 492 "gpcb-menu.res" char *s = N_("Unselect all objects"); # 463 "gpcb-menu.res" char *s = N_("Up"); # 173 "gpcb-menu.res" char *s = N_("V"); # 165 "gpcb-menu.res" char *s = N_("Value"); # 232 "gpcb-menu.res" char *s = N_("Vendor drill mapping"); # 521 "gpcb-menu.res" char *s = N_("Via"); # 450 "gpcb-menu.res" char *s = N_("Via Tool drill +5 mil"); # 451 "gpcb-menu.res" char *s = N_("Via Tool drill -5 mil"); # 448 "gpcb-menu.res" char *s = N_("Via Tool size +5 mil"); # 449 "gpcb-menu.res" char *s = N_("Via Tool size -5 mil"); # 123 "gpcb-menu.res" char *s = N_("Via type"); # 360 "gpcb-menu.res" char *s = N_("Vianudge"); # 261 "gpcb-menu.res" char *s = N_("Vias"); # 292 "gpcb-menu.res" char *s = N_("Vias +10 mil"); # 291 "gpcb-menu.res" char *s = N_("Vias -10 mil"); # 361 "gpcb-menu.res" char *s = N_("Viatrim"); # 133 "gpcb-menu.res" char *s = N_("View"); # 453 "gpcb-menu.res" char *s = N_("W"); # 475 "gpcb-menu.res" char *s = N_("Window"); # 125 "gpcb-menu.res" char *s = N_("Xtrl-Shift-F"); # 124 "gpcb-menu.res" char *s = N_("Xtrl-Shift-P"); # 126 "gpcb-menu.res" char *s = N_("Xtrl-Shift-T"); # 365 "gpcb-menu.res" char *s = N_("Y"); # 170 "gpcb-menu.res" char *s = N_("Z"); # 169 "gpcb-menu.res" /* xgettext:no-c-format */ char *s = N_("Zoom In 20%"); # 182 "gpcb-menu.res" /* xgettext:no-c-format */ char *s = N_("Zoom In 20% and center"); # 174 "gpcb-menu.res" char *s = N_("Zoom In 2X"); # 173 "gpcb-menu.res" char *s = N_("Zoom Max"); # 170 "gpcb-menu.res" /* xgettext:no-c-format */ char *s = N_("Zoom Out 20%"); # 183 "gpcb-menu.res" /* xgettext:no-c-format */ char *s = N_("Zoom Out 20% and center"); # 175 "gpcb-menu.res" char *s = N_("Zoom Out 2X"); # 177 "gpcb-menu.res" char *s = N_("Zoom to 0.01mm/px"); # 179 "gpcb-menu.res" char *s = N_("Zoom to 0.05mm/px"); # 176 "gpcb-menu.res" char *s = N_("Zoom to 0.1mil/px"); # 181 "gpcb-menu.res" char *s = N_("Zoom to 0.1mm/px"); # 182 "gpcb-menu.res" char *s = N_("Zoom to 10mil/px"); # 178 "gpcb-menu.res" char *s = N_("Zoom to 1mil/px"); # 180 "gpcb-menu.res" char *s = N_("Zoom to 2.5mil/px"); # 456 "gpcb-menu.res" char *s = N_("["); # 457 "gpcb-menu.res" char *s = N_("]"); # 110 "gpcb-menu.res" char *s = N_("active layer"); # 65 "gpcb-menu.res" char *s = N_("gschem"); # 476 "gpcb-menu.res" char *s = N_("i"); # 109 "gpcb-menu.res" char *s = N_("layout"); # 136 "gpcb-menu.res" char *s = N_("mil"); # 137 "gpcb-menu.res" char *s = N_("mm"); # 108 "gpcb-menu.res" char *s = N_("text on layout"); # 227 "gpcb-menu.res" char *s = N_("|"); pcb-4.2.2/src/macro.h0000664000076400007640000004215213533277055011275 00000000000000/*! * \file src/macro.h * * \brief Some commonly used macros not related to a special C-file. * * The file is included by global.h after const.h * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifndef PCB_MACRO_H #define PCB_MACRO_H /* --------------------------------------------------------------------------- * macros to transform coord systems * draw.c uses a different definition of TO_SCREEN */ #ifndef SWAP_IDENT #define SWAP_IDENT Settings.ShowBottomSide #endif #define SWAP_SIGN_X(x) (x) #define SWAP_SIGN_Y(y) (-(y)) #define SWAP_ANGLE(a) (-(a)) #define SWAP_DELTA(d) (-(d)) #define SWAP_X(x) (SWAP_SIGN_X(x)) #define SWAP_Y(y) (PCB->MaxHeight +SWAP_SIGN_Y(y)) /* --------------------------------------------------------------------------- * misc macros, some might already be defined by */ #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef SGN #define SGN(a) ((a) >0 ? 1 : ((a) == 0 ? 0 : -1)) #endif #define SGNZ(a) ((a) >=0 ? 1 : -1) #define MAKEMIN(a,b) if ((b) < (a)) (a) = (b) #define MAKEMAX(a,b) if ((b) > (a)) (a) = (b) #define ARG(n) (argc > (n) ? argv[n] : 0) #define ENTRIES(x) (sizeof((x))/sizeof((x)[0])) #define UNKNOWN(a) ((a) && *(a) ? (a) : "(unknown)") #define UNKNOWN_NAME(a, n) ((a) && *(a) ? (a) : (n)) #define NSTRCMP(a, b) ((a) ? ((b) ? strcmp((a),(b)) : 1) : -1) #define EMPTY(a) ((a) ? (a) : "") #define EMPTY_STRING_P(a) ((a) ? (a)[0]==0 : 1) #define XOR(a,b) (((a) && !(b)) || (!(a) && (b))) #define SQUARE(x) ((float) (x) * (float) (x)) #define TO_RADIANS(degrees) (M180 * (degrees)) /* Proper rounding for double -> Coord. */ #define DOUBLE_TO_COORD(x) ((x) >= 0 ? (Coord)((x) + 0.5) : (Coord)((x) - 0.5)) /* --------------------------------------------------------------------------- * layer macros */ #define LAYER_ON_STACK(n) (&PCB->Data->Layer[LayerStack[(n)]]) #define LAYER_PTR(n) (&PCB->Data->Layer[(n)]) #define CURRENT (PCB->SilkActive ? &PCB->Data->Layer[ \ (Settings.ShowBottomSide ? bottom_silk_layer : top_silk_layer)] \ : LAYER_ON_STACK(0)) #define INDEXOFCURRENT (PCB->SilkActive ? \ (Settings.ShowBottomSide ? bottom_silk_layer : top_silk_layer) \ : LayerStack[0]) #define SILKLAYER Layer[ \ (Settings.ShowBottomSide ? bottom_silk_layer : top_silk_layer)] #define BACKSILKLAYER Layer[ \ (Settings.ShowBottomSide ? top_silk_layer : bottom_silk_layer)] #define TEST_SILK_LAYER(layer) (GetLayerNumber (PCB->Data, layer) >= max_copper_layer) /* --------------------------------------------------------------------------- * returns the object ID */ #define OBJECT_ID(p) (((AnyObjectType *) p)->ID) /* --------------------------------------------------------------------------- * access macro for current buffer */ #define PASTEBUFFER (&Buffers[Settings.BufferNumber]) /* flag macros moved to flag.h */ /* --------------------------------------------------------------------------- * access macros for elements name structure */ #define DESCRIPTION_INDEX 0 #define NAMEONPCB_INDEX 1 #define VALUE_INDEX 2 #define NAME_INDEX(p) (TEST_FLAG(NAMEONPCBFLAG,(p)) ? NAMEONPCB_INDEX :\ (TEST_FLAG(DESCRIPTIONFLAG, (p)) ? \ DESCRIPTION_INDEX : VALUE_INDEX)) #define ELEMENT_NAME(p,e) ((e)->Name[NAME_INDEX((p))].TextString) #define DESCRIPTION_NAME(e) ((e)->Name[DESCRIPTION_INDEX].TextString) #define NAMEONPCB_NAME(e) ((e)->Name[NAMEONPCB_INDEX].TextString) #define VALUE_NAME(e) ((e)->Name[VALUE_INDEX].TextString) #define ELEMENT_TEXT(p,e) ((e)->Name[NAME_INDEX((p))]) #define DESCRIPTION_TEXT(e) ((e)->Name[DESCRIPTION_INDEX]) #define NAMEONPCB_TEXT(e) ((e)->Name[NAMEONPCB_INDEX]) #define VALUE_TEXT(e) ((e)->Name[VALUE_INDEX]) /* --------------------------------------------------------------------------- * Determines if text is actually visible */ #define TEXT_IS_VISIBLE(b, l, t) \ ((l)->On) /* --------------------------------------------------------------------------- * Determines if object is on front or back */ #define FRONT(o) \ ((TEST_FLAG(ONSOLDERFLAG, (o)) != 0) == SWAP_IDENT) /* --------------------------------------------------------------------------- * Determines if an object is on the given side. side is either BOTTOM_GROUP * or TOP_GROUP. */ #define ON_SIDE(element, side) \ (TEST_FLAG (ONSOLDERFLAG, element) == (side == BOTTOM_SIDE)) /* --------------------------------------------------------------------------- * some loop shortcuts * * a pointer is created from index addressing because the base pointer * may change when new memory is allocated; * * all data is relativ to an objects name 'top' which can be either * PCB or PasteBuffer */ #define END_LOOP }} while (0) #define STYLE_LOOP(top) do { \ Cardinal n; \ RouteStyleType *style; \ for (n = 0; n < NUM_STYLES; n++) \ { \ style = &(top)->RouteStyle[n] #define VIA_LOOP(top) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (top)->Via, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ PinType *via = __iter->data; #define DRILL_LOOP(top) do { \ Cardinal n; \ DrillType *drill; \ for (n = 0; (top)->DrillN > 0 && n < (top)->DrillN; n++) \ { \ drill = &(top)->Drill[n] #define NETLIST_LOOP(top) do { \ Cardinal n; \ NetListType *netlist; \ for (n = (top)->NetListN-1; n != -1; n--) \ { \ netlist = &(top)->NetList[n] #define NET_LOOP(top) do { \ Cardinal n; \ NetType *net; \ for (n = (top)->NetN-1; n != -1; n--) \ { \ net = &(top)->Net[n] #define CONNECTION_LOOP(net) do { \ Cardinal n; \ ConnectionType *connection; \ for (n = (net)->ConnectionN-1; n != -1; n--) \ { \ connection = & (net)->Connection[n] #define ELEMENT_LOOP(top) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (top)->Element, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ ElementType *element = __iter->data; #define RAT_LOOP(top) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (top)->Rat, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ RatType *line = __iter->data; #define ELEMENTTEXT_LOOP(element) do { \ Cardinal n; \ TextType *text; \ for (n = MAX_ELEMENTNAMES-1; n != -1; n--) \ { \ text = &(element)->Name[n] #define ELEMENTNAME_LOOP(element) do { \ Cardinal n; \ char *textstring; \ for (n = MAX_ELEMENTNAMES-1; n != -1; n--) \ { \ textstring = (element)->Name[n].TextString #define PIN_LOOP(element) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (element)->Pin, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ PinType *pin = __iter->data; #define PAD_LOOP(element) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (element)->Pad, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ PadType *pad = __iter->data; #define ARC_LOOP(element) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (element)->Arc, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ ArcType *arc = __iter->data; #define ELEMENTLINE_LOOP(element) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (element)->Line, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ LineType *line = __iter->data; #define ELEMENTARC_LOOP(element) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (element)->Arc, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ ArcType *arc = __iter->data; #define LINE_LOOP(layer) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (layer)->Line, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ LineType *line = __iter->data; #define TEXT_LOOP(layer) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (layer)->Text, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ TextType *text = __iter->data; #define POLYGON_LOOP(layer) do { \ GList *__iter, *__next; \ Cardinal n = 0; \ for (__iter = (layer)->Polygon, __next = g_list_next (__iter); \ __iter != NULL; \ __iter = __next, __next = g_list_next (__iter), n++) { \ PolygonType *polygon = __iter->data; #define POLYGONPOINT_LOOP(polygon) do { \ Cardinal n; \ PointType *point; \ for (n = (polygon)->PointN-1; n != -1; n--) \ { \ point = &(polygon)->Points[n] #define ENDALL_LOOP }} while (0); }} while(0) #define ALLPIN_LOOP(top) \ ELEMENT_LOOP(top); \ PIN_LOOP(element)\ #define ALLPAD_LOOP(top) \ ELEMENT_LOOP(top); \ PAD_LOOP(element) #define ALLLINE_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ LINE_LOOP(layer) #define ALLARC_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l =0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ ARC_LOOP(layer) #define ALLPOLYGON_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ POLYGON_LOOP(layer) #define COPPERLINE_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer; l++, layer++) \ { \ LINE_LOOP(layer) #define COPPERARC_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l =0; l < max_copper_layer; l++, layer++) \ { \ ARC_LOOP(layer) #define COPPERPOLYGON_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer; l++, layer++) \ { \ POLYGON_LOOP(layer) #define SILKLINE_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ layer += max_copper_layer + BOTTOM_SILK_LAYER; \ for (l = 0; l < 2; l++, layer++) \ { \ LINE_LOOP(layer) #define SILKARC_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ layer += max_copper_layer + BOTTOM_SILK_LAYER; \ for (l = 0; l < 2; l++, layer++) \ { \ ARC_LOOP(layer) #define SILKPOLYGON_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ layer += max_copper_layer + BOTTOM_SILK_LAYER; \ for (l = 0; l < 2; l++, layer++) \ { \ POLYGON_LOOP(layer) #define ALLTEXT_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ TEXT_LOOP(layer) #define VISIBLELINE_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ if (layer->On) \ LINE_LOOP(layer) #define VISIBLEARC_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ if (layer->On) \ ARC_LOOP(layer) #define VISIBLETEXT_LOOP(board) do { \ Cardinal l; \ LayerType *layer = (board)->Data->Layer; \ for (l = 0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ TEXT_LOOP(layer); \ if (TEXT_IS_VISIBLE((board), layer, text)) #define VISIBLEPOLYGON_LOOP(top) do { \ Cardinal l; \ LayerType *layer = (top)->Layer; \ for (l = 0; l < max_copper_layer + SILK_LAYER; l++, layer++) \ { \ if (layer->On) \ POLYGON_LOOP(layer) #define POINTER_LOOP(top) do { \ Cardinal n; \ void **ptr; \ for (n = (top)->PtrN-1; n != -1; n--) \ { \ ptr = &(top)->Ptr[n] #define MENU_LOOP(top) do { \ Cardinal l; \ LibraryMenuType *menu; \ for (l = (top)->MenuN-1; l != -1; l--) \ { \ menu = &(top)->Menu[l] #define ENTRY_LOOP(top) do { \ Cardinal n; \ LibraryEntryType *entry; \ for (n = (top)->EntryN-1; n != -1; n--) \ { \ entry = &(top)->Entry[n] #define GROUP_LOOP(data, group) do { \ Cardinal entry; \ for (entry = 0; entry < ((PCBType *)(data->pcb))->LayerGroups.Number[(group)]; entry++) \ { \ LayerType *layer; \ Cardinal number; \ number = ((PCBType *)(data->pcb))->LayerGroups.Entries[(group)][entry]; \ if (number >= max_copper_layer) \ continue; \ layer = &data->Layer[number]; #define LAYER_LOOP(data, ml) do { \ Cardinal n; \ for (n = 0; n < ml; n++) \ { \ LayerType *layer = (&data->Layer[(n)]); #define LAYER_TYPE_LOOP(data, ml, type) do { \ Cardinal n; \ for (n = 0; n < ml; n++) { \ LayerType *layer = (&data->Layer[(n)]); \ if (layer->Type != (type)) \ continue; #endif #define VIA_IS_BURIED(via) (via->BuriedFrom != 0 || via->BuriedTo != 0) #define VIA_ON_LAYER(via, layer) (layer >= via->BuriedFrom && layer <= via->BuriedTo ) pcb-4.2.2/src/thermal.c0000664000076400007640000004102113604156111011601 00000000000000/*! * \file src/thermal.c * * \brief Negative thermal finger polygons. * * Thermals are normal lines on the layout * * The only thing unique about them is that they have the USETHERMALFLAG * set so that they can be identified as thermals. * * It is handy for pcb to automatically make adjustments to the thermals * when the user performs certain operations, and the functions in * thermal.h help implement that. * * \author This file, thermal.c was written by and is * (C) Copyright 2006, harry eaton * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996,2004,2006 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STRING_H #include #endif #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_PWD_H #include #endif #include "global.h" #include "create.h" #include "data.h" #include "draw.h" #include "error.h" #include "misc.h" #include "move.h" #include "polygon.h" #include "rtree.h" #include "thermal.h" #include "undo.h" #ifdef HAVE_LIBDMALLOC #include #endif static PCBType *pcb; struct cent { Coord x, y; Coord s, c; char style; POLYAREA *p; }; static POLYAREA * diag_line (Coord X, Coord Y, Coord l, Coord w, bool rt) { PLINE *c; Vector v; Coord x1, x2, y1, y2; if (rt) { x1 = (l - w) * M_SQRT1_2; x2 = (l + w) * M_SQRT1_2; y1 = x1; y2 = x2; } else { x2 = -(l - w) * M_SQRT1_2; x1 = -(l + w) * M_SQRT1_2; y1 = -x1; y2 = -x2; } v[0] = X + x1; v[1] = Y + y2; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = X - x2; v[1] = Y - y1; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = X - x1; v[1] = Y - y2; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = X + x2; v[1] = Y + y1; poly_InclVertex (c->head.prev, poly_CreateNode (v)); return ContourToPoly (c); } static POLYAREA * square_therm (PinType *pin, Cardinal style) { POLYAREA *p, *p2; PLINE *c; Vector v; Coord d, in, out; switch (style) { case 1: /* This is the style where the thermals come out of the corners of the * square. We create this by removing four trapezoids from the polygon. * * The d variable is the offset from the corner of the pad/cutout required * to produce the diagonal line of the appropriate thickness. If you draw * a hypotenuse of length (clearance * thermscale) in the corner of the * square, you create a 1:1:sqrt(2) triangle. The length of the "1" sides * is the width of the line divided by the sqrt(2). * */ d = pcb->ThermScale * pin->Clearance * M_SQRT1_2; out = (pin->Thickness + pin->Clearance) / 2; in = pin->Thickness / 2; /* top (actually bottom since +y is down) */ v[0] = pin->X - in + d; v[1] = pin->Y + in; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X + in - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + out - d; v[1] = pin->Y + out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - out + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p = ContourToPoly (c); /* right */ v[0] = pin->X + in; v[1] = pin->Y + in - d; if ((c = poly_NewContour (v)) == NULL) return NULL; v[1] = pin->Y - in + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + out; v[1] = pin->Y - out + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y + out - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p2 = ContourToPoly (c); p->f = p2; p2->b = p; /* left */ v[0] = pin->X - in; v[1] = pin->Y - in + d; if ((c = poly_NewContour (v)) == NULL) return NULL; v[1] = pin->Y + in - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - out; v[1] = pin->Y + out - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y - out + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p2 = ContourToPoly (c); p->f->f = p2; p2->b = p->f; /* bottom (actually top since +y is down) */ v[0] = pin->X + in - d; v[1] = pin->Y - in; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X - in + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - out + d; v[1] = pin->Y - out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + out - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); p2 = ContourToPoly (c); p->f->f->f = p2; p2->f = p; p2->b = p->f->f; p->b = p2; return p; case 4: { /* This version has four lines coming out of the corners, but the edges * are all rounded. It's created by subtracting four lines from the * polygon that run along the edge pin. * */ LineType l; l.Flags = NoFlags (); d = pin->Thickness / 2 - pcb->ThermScale * pin->Clearance; out = pin->Thickness / 2 + pin->Clearance / 4; in = pin->Clearance / 2; /* top */ l.Point1.X = pin->X - d; l.Point2.Y = l.Point1.Y = pin->Y + out; l.Point2.X = pin->X + d; p = LinePoly (&l, in); /* right */ l.Point1.X = l.Point2.X = pin->X + out; l.Point1.Y = pin->Y - d; l.Point2.Y = pin->Y + d; p2 = LinePoly (&l, in); p->f = p2; p2->b = p; /* bottom */ l.Point1.X = pin->X - d; l.Point2.Y = l.Point1.Y = pin->Y - out; l.Point2.X = pin->X + d; p2 = LinePoly (&l, in); p->f->f = p2; p2->b = p->f; /* left */ l.Point1.X = l.Point2.X = pin->X - out; l.Point1.Y = pin->Y - d; l.Point2.Y = pin->Y + d; p2 = LinePoly (&l, in); p->f->f->f = p2; p2->b = p->f->f; p->b = p2; p2->f = p; return p; } default: /* style 2 and 5 */ /* These styles have the fingers coming out the top, bottom and sides. We * create these by carving out contours around the corners. If we're doing * style 5, the corners are square, and if we're doing style 2, the * corners are round. * */ d = 0.5 * pcb->ThermScale * pin->Clearance; if (style == 5) d += d; out = (pin->Thickness + pin->Clearance) / 2; in = pin->Thickness / 2; /* "top" right */ /* Start at the lower right hand corner of the pin. */ v[0] = pin->X + in; v[1] = pin->Y + in; if ((c = poly_NewContour (v)) == NULL) return NULL; /* Move up to the point where the bottom of the right finger meets the * pin. If we're doing round corners, d is bigger to account for the arc * */ v[1] = pin->Y + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* Either go straight or arc over to the point where the lower edge of the * right finger meets the bulk of the polygon. * */ if (style == 2) { v[0] = pin->X + out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2); /* Move to the bottom right corner. Both styles use arcs around the outer * corners, so, arc around to the bottom edge. */ v[1] = pin->Y + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point */ frac_circle (c, pin->X + in, pin->Y + in, v, 4); /* The corner where the right side of the bottom finger meets the bulk of * the polygon. If we're doing the rounded style, this has already been * adjusted for the raidus of the arc. * */ v[0] = pin->X + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* Either straight, or arc to the point where the right side of the bottom * finger meets the pad. * */ if (style == 2) { poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2); /* We don't have to add the starting vertext a second time, so, we're * done! */ p = ContourToPoly (c); /* Now do the other three corners... */ /* "bottom" right */ v[0] = pin->X + in; v[1] = pin->Y - d; if ((c = poly_NewContour (v)) == NULL) return NULL; v[1] = pin->Y - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { v[1] = pin->Y - out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0], v[1] - pin->Clearance / 4, v, 2); v[0] = pin->X + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point */ frac_circle (c, pin->X + in, pin->Y - in, v, 4); v[1] = pin->Y - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 5) frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2); p2 = ContourToPoly (c); p->f = p2; p2->b = p; /* "bottom" left */ v[0] = pin->X - d; v[1] = pin->Y - in; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[1] = pin->Y - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { v[0] = pin->X - out; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0] - pin->Clearance / 4, v[1], v, 2); v[1] = pin->Y - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point */ frac_circle (c, pin->X - in, pin->Y - in, v, 4); v[0] = pin->X - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 5) frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2); p2 = ContourToPoly (c); p->f->f = p2; p2->b = p->f; /* "top" left */ v[0] = pin->X - d; v[1] = pin->Y + out; if ((c = poly_NewContour (v)) == NULL) return NULL; v[0] = pin->X - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); /* pivot 1/4 circle to next point (x-out, y+in) */ frac_circle (c, pin->X - in, pin->Y + in, v, 4); v[1] = pin->Y + d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 2) { v[0] = pin->X - in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); } else frac_circle (c, v[0] + pin->Clearance / 4, v[1], v, 2); v[1] = pin->Y + in; poly_InclVertex (c->head.prev, poly_CreateNode (v)); v[0] = pin->X - d; poly_InclVertex (c->head.prev, poly_CreateNode (v)); if (style == 5) frac_circle (c, v[0], v[1] + pin->Clearance / 4, v, 2); p2 = ContourToPoly (c); p->f->f->f = p2; p2->f = p; p2->b = p->f->f; p->b = p2; return p; } } static POLYAREA * oct_therm (PinType *pin, Cardinal style) { POLYAREA *p, *p2, *m; Coord t = 0.5 * pcb->ThermScale * pin->Clearance; Coord w = pin->Thickness + pin->Clearance; p = OctagonPoly (pin->X, pin->Y, w); p2 = OctagonPoly (pin->X, pin->Y, pin->Thickness); /* make full clearance ring */ poly_Boolean_free (p, p2, &m, PBO_SUB); switch (style) { default: case 1: p = diag_line (pin->X, pin->Y, w, t, true); poly_Boolean_free (m, p, &p2, PBO_SUB); p = diag_line (pin->X, pin->Y, w, t, false); poly_Boolean_free (p2, p, &m, PBO_SUB); return m; case 2: p = RectPoly (pin->X - t, pin->X + t, pin->Y - w, pin->Y + w); poly_Boolean_free (m, p, &p2, PBO_SUB); p = RectPoly (pin->X - w, pin->X + w, pin->Y - t, pin->Y + t); poly_Boolean_free (p2, p, &m, PBO_SUB); return m; /* fix me add thermal style 4 */ case 5: { Coord t = pin->Thickness / 2; POLYAREA *q; /* cheat by using the square therm's rounded parts */ p = square_therm (pin, style); q = RectPoly (pin->X - t, pin->X + t, pin->Y - t, pin->Y + t); poly_Boolean_free (p, q, &p2, PBO_UNITE); poly_Boolean_free (m, p2, &p, PBO_ISECT); return p; } } } /*! * \brief . * * \return ThermPoly returns a POLYAREA having all of the clearance that * when subtracted from the plane create the desired thermal fingers. * Usually this is 4 disjoint regions. */ POLYAREA * ThermPoly (PCBType *p, PinType *pin, Cardinal laynum) { ArcType a; POLYAREA *pa, *arc; Cardinal style = GET_THERM (laynum, pin); if (style == 3) return NULL; /* solid connection no clearance */ pcb = p; if (TEST_FLAG (SQUAREFLAG, pin)) return square_therm (pin, style); if (TEST_FLAG (OCTAGONFLAG, pin)) return oct_therm (pin, style); /* must be circular */ switch (style) { case 1: case 2: { POLYAREA *m; Coord t = (pin->Thickness + pin->Clearance) / 2; Coord w = 0.5 * pcb->ThermScale * pin->Clearance; pa = CirclePoly (pin->X, pin->Y, t); arc = CirclePoly (pin->X, pin->Y, pin->Thickness / 2); /* create a thin ring */ poly_Boolean_free (pa, arc, &m, PBO_SUB); /* fix me needs error checking */ if (style == 2) { /* t is the theoretically required length, but we use twice that * to avoid descritisation errors in our circle approximation. */ pa = RectPoly (pin->X - t * 2, pin->X + t * 2, pin->Y - w, pin->Y + w); poly_Boolean_free (m, pa, &arc, PBO_SUB); pa = RectPoly (pin->X - w, pin->X + w, pin->Y - t * 2, pin->Y + t * 2); } else { /* t is the theoretically required length, but we use twice that * to avoid descritisation errors in our circle approximation. */ pa = diag_line (pin->X, pin->Y, t * 2, w, true); poly_Boolean_free (m, pa, &arc, PBO_SUB); pa = diag_line (pin->X, pin->Y, t * 2, w, false); } poly_Boolean_free (arc, pa, &m, PBO_SUB); return m; } default: a.X = pin->X; a.Y = pin->Y; a.Height = a.Width = pin->Thickness / 2 + pin->Clearance / 4; a.Thickness = 1; a.Clearance = pin->Clearance / 2; a.Flags = NoFlags (); a.Delta = 90 - (a.Clearance * (1. + 2. * pcb->ThermScale) * 180) / (M_PI * a.Width); a.StartAngle = 90 - a.Delta / 2 + (style == 4 ? 0 : 45); pa = ArcPoly (&a, a.Clearance); if (!pa) return NULL; a.StartAngle += 90; arc = ArcPoly (&a, a.Clearance); if (!arc) return NULL; pa->f = arc; arc->b = pa; a.StartAngle += 90; arc = ArcPoly (&a, a.Clearance); if (!arc) return NULL; pa->f->f = arc; arc->b = pa->f; a.StartAngle += 90; arc = ArcPoly (&a, a.Clearance); if (!arc) return NULL; pa->b = arc; pa->f->f->f = arc; arc->b = pa->f->f; arc->f = pa; pa->b = arc; return pa; } } pcb-4.2.2/src/dbus-pcbmain.h0000664000076400007640000000225013434555140012525 00000000000000/*! * \file src/dbus-pacbmain.h * * \brief D-Bus IPC logic * * PCB, an interactive printed circuit board editor * * Copyright (C) 2006 University of Cambridge * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef PCB_DBUS_PCBMAIN_H #define PCB_DBUS_PCBMAIN_H #define DBUS_API_SUBJECT_TO_CHANGE #include void pcb_dbus_connection_setup_with_mainloop (DBusConnection * connection); void pcb_dbus_connection_finish_with_mainloop (DBusConnection * connection); #endif /* !PCB_DBUS_PCBMAIN_H */ pcb-4.2.2/src/res_parse.h0000664000076400007640000000433213036701364012146 00000000000000 /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton interface for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { STRING = 258, INCLUDE = 259 }; #endif /* Tokens. */ #define STRING 258 #define INCLUDE 259 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE { /* Line 1676 of yacc.c */ #line 40 "res_parse.y" int ival; char *sval; Resource *rval; /* Line 1676 of yacc.c */ #line 68 "res_parse.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE reslval; pcb-4.2.2/src/main.c0000664000076400007640000016042413533277055011116 00000000000000/*! * \file src/main.c * * \brief Main program, initializes some stuff and handles user input. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996, 2004 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #ifdef HAVE_STRING_H #include #endif #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H) #include #endif #include #include #include #include /* Seed for srand() */ #include "global.h" #include "data.h" #include "buffer.h" #include "create.h" #include "crosshair.h" #include "draw.h" #include "error.h" #include "file.h" #include "set.h" #include "action.h" #include "misc.h" #include "lrealpath.h" #include "free_atexit.h" #include "polygon.h" #include "gettext.h" #include "pcb-printf.h" #include "strflags.h" #include "hid/common/actions.h" /* This next one is so we can print the help messages. */ #include "hid/hidint.h" #ifdef HAVE_DBUS #include "dbus.h" #endif #ifdef HAVE_LIBDMALLOC #include #endif #define PCBLIBPATH ".:" PCBLIBDIR #ifdef HAVE_LIBSTROKE extern void stroke_init (void); #endif /*! * \brief Initialize signal and error handlers. */ static void InitHandler (void) { /* signal(SIGHUP, CatchSignal); signal(SIGQUIT, CatchSignal); signal(SIGABRT, CatchSignal); signal(SIGSEGV, CatchSignal); signal(SIGTERM, CatchSignal); signal(SIGINT, CatchSignal); */ /* calling external program by popen() may cause a PIPE signal, * so we ignore it */ #ifdef SIGPIPE signal (SIGPIPE, SIG_IGN); #endif } /* ---------------------------------------------------------------------- | command line and rc file processing. */ static char *command_line_pcb; /*! * \brief Print the copyright notice. */ void copyright (void) { printf ("\n" " COPYRIGHT for %s version %s\n\n" " PCB, interactive printed circuit board design\n" " Copyright (C) 1994,1995,1996,1997 Thomas Nau\n" " Copyright (C) 1998, 1999, 2000 Harry Eaton\n\n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" " (at your option) any later version.\n\n" " This program is distributed in the hope that it will be useful,\n" " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" " GNU General Public License for more details.\n\n" " You should have received a copy of the GNU General Public License along\n" " with this program; if not, write to the Free Software Foundation, Inc.,\n" " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\n", Progname, VERSION); exit (0); } static inline void u (const char *fmt, ...) { va_list ap; va_start (ap, fmt); vfprintf (stderr, fmt, ap); fputc ('\n', stderr); va_end (ap); } typedef struct UsageNotes { struct UsageNotes *next; HID_Attribute *seen; } UsageNotes; static UsageNotes *usage_notes = NULL; static void usage_attr (HID_Attribute * a) { int i, n; const Unit *unit_list; static char buf[200]; if (a->help_text == ATTR_UNDOCUMENTED) return; switch (a->type) { case HID_Label: return; case HID_Integer: case HID_Real: sprintf (buf, "--%s ", a->name); break; case HID_Coord: sprintf (buf, "--%s ", a->name); break; case HID_String: sprintf (buf, "--%s ", a->name); break; case HID_Boolean: sprintf (buf, "--%s", a->name); break; case HID_Mixed: case HID_Enum: sprintf (buf, "--%s ", a->name); if (a->type == HID_Mixed) strcat (buf, " "); for (i = 0; a->enumerations[i]; i++) { strcat (buf, i ? "|" : "<"); strcat (buf, a->enumerations[i]); } strcat (buf, ">"); break; case HID_Path: sprintf (buf, "--%s ", a->name); break; case HID_Unit: unit_list = get_unit_list (); n = get_n_units (); sprintf (buf, "--%s ", a->name); for (i = 0; i < n; i++) { strcat (buf, i ? "|" : "<"); strcat (buf, unit_list[i].suffix); } strcat (buf, ">"); break; } if (strlen (buf) <= 30) { if (a->help_text) fprintf (stderr, " %-30s\t%s\n", buf, a->help_text); else fprintf (stderr, " %-30s\n", buf); } else if (a->help_text && strlen (a->help_text) + strlen (buf) < 72) fprintf (stderr, " %s\t%s\n", buf, a->help_text); else if (a->help_text) fprintf (stderr, " %s\n\t\t\t%s\n", buf, a->help_text); else fprintf (stderr, " %s\n", buf); } static void usage_hid (HID * h) { HID_Attribute *attributes; int i, n_attributes = 0; UsageNotes *note; if (h->gui) { fprintf (stderr, "\n%s gui options:\n", h->name); attributes = h->get_export_options (&n_attributes); } else { fprintf (stderr, "\n%s options:\n", h->name); exporter = h; attributes = exporter->get_export_options (&n_attributes); exporter = NULL; } note = (UsageNotes *)malloc (sizeof (UsageNotes)); note->next = usage_notes; note->seen = attributes; usage_notes = note; for (i = 0; i < n_attributes; i++) usage_attr (attributes + i); } static void usage (void) { HID **hl = hid_enumerate (); HID_AttrNode *ha; UsageNotes *note; int i; int n_printer = 0, n_gui = 0, n_exporter = 0; for (i = 0; hl[i]; i++) { if (hl[i]->gui) n_gui++; if (hl[i]->printer) n_printer++; if (hl[i]->exporter) n_exporter++; } u ("PCB Printed Circuit Board editing program, http://pcb.geda-project.org"); u ("%s [-h|-V|--copyright]\t\t\tHelp, version, copyright", Progname); u ("%s [gui options] \t\tto edit", Progname); u ("Available GUI hid%s:", n_gui == 1 ? "" : "s"); for (i = 0; hl[i]; i++) if (hl[i]->gui) fprintf (stderr, "\t%-8s %s\n", hl[i]->name, hl[i]->description); u ("%s -p [printing options] \tto print", Progname); u ("Available printing hid%s:", n_printer == 1 ? "" : "s"); for (i = 0; hl[i]; i++) if (hl[i]->printer) fprintf (stderr, "\t%-8s %s\n", hl[i]->name, hl[i]->description); u ("%s -x hid [export options] \tto export", Progname); u ("Available export hid%s:", n_exporter == 1 ? "" : "s"); for (i = 0; hl[i]; i++) if (hl[i]->exporter) fprintf (stderr, "\t%-8s %s\n", hl[i]->name, hl[i]->description); for (i = 0; hl[i]; i++) if (hl[i]->gui) usage_hid (hl[i]); for (i = 0; hl[i]; i++) if (hl[i]->printer) usage_hid (hl[i]); for (i = 0; hl[i]; i++) if (hl[i]->exporter) usage_hid (hl[i]); u ("\nCommon options:"); for (ha = hid_attr_nodes; ha; ha = ha->next) { for (note = usage_notes; note && note->seen != ha->attributes; note = note->next) ; if (note) continue; for (i = 0; i < ha->n; i++) { usage_attr (ha->attributes + i); } } exit (1); } static void print_defaults_1 (HID_Attribute * a, void *value) { int i; Coord c; double d; const char *s; /* Remember, at this point we've parsed the command line, so they may be in the global variable instead of the default_val. */ switch (a->type) { case HID_Integer: i = value ? *(int *) value : a->default_val.int_value; fprintf (stderr, "%s %d\n", a->name, i); break; case HID_Boolean: i = value ? *(char *) value : a->default_val.int_value; fprintf (stderr, "%s %s\n", a->name, i ? "yes" : "no"); break; case HID_Real: d = value ? *(double *) value : a->default_val.real_value; fprintf (stderr, "%s %g\n", a->name, d); break; case HID_Coord: c = value ? *(Coord *) value : a->default_val.coord_value; pcb_fprintf (stderr, "%s %$mS\n", a->name, c); break; case HID_String: case HID_Path: s = value ? *(char **) value : a->default_val.str_value; fprintf (stderr, "%s \"%s\"\n", a->name, s); break; case HID_Enum: i = value ? *(int *) value : a->default_val.int_value; fprintf (stderr, "%s %s\n", a->name, a->enumerations[i]); break; case HID_Mixed: i = value ? ((HID_Attr_Val*)value)->int_value : a->default_val.int_value; d = value ? ((HID_Attr_Val*)value)->real_value : a->default_val.real_value; fprintf (stderr, "%s %g%s\n", a->name, d, a->enumerations[i]); break; case HID_Label: break; case HID_Unit: i = value ? *(int *) value : a->default_val.int_value; fprintf (stderr, "%s %s\n", a->name, get_unit_list()[i].suffix); } } static void print_defaults () { HID **hl = hid_enumerate (); HID_Attribute *e; int i, n, hi; for (hi = 0; hl[hi]; hi++) { HID *h = hl[hi]; if (h->gui) { HID_AttrNode *ha; fprintf (stderr, "\ngui defaults:\n"); for (ha = hid_attr_nodes; ha; ha = ha->next) for (i = 0; i < ha->n; i++) print_defaults_1 (ha->attributes + i, ha->attributes[i].value); } else { fprintf (stderr, "\n%s defaults:\n", h->name); exporter = h; e = exporter->get_export_options (&n); exporter = NULL; if (e) for (i = 0; i < n; i++) print_defaults_1 (e + i, 0); } } exit (1); } #define SSET(F,D,N,H) { N, H, \ HID_String, 0, 0, { 0, D, 0 }, 0, &Settings.F } #define ISET(F,D,N,H) { N, H, \ HID_Integer, 0, 0, { D, 0, 0 }, 0, &Settings.F } #define BSET(F,D,N,H) { N, H, \ HID_Boolean, 0, 0, { D, 0, 0 }, 0, &Settings.F } #define RSET(F,D,N,H) { N, H, \ HID_Real, 0, 0, { 0, 0, D }, 0, &Settings.F } #define CSET(F,D,N,H) { N, H, \ HID_Coord, 0, 0, { 0, 0, 0, D }, 0, &Settings.F } #define COLOR(F,D,N,H) { N, H, \ HID_String, 0, 0, { 0, D, 0 }, 0, &Settings.F } #define LAYERCOLOR(N,D) { "layer-color-" #N, "Color for layer " #N, \ HID_String, 0, 0, { 0, D, 0 }, 0, &Settings.LayerColor[N-1] } #define LAYERNAME(N,D) { "layer-name-" #N, "Name for layer " #N, \ HID_String, 0, 0, { 0, D, 0 }, 0, &Settings.DefaultLayerName[N-1] } #define LAYERSELCOLOR(N) { "layer-selected-color-" #N, "Color for layer " #N " when selected", \ HID_String, 0, 0, { 0, "#00ffff", 0 }, 0, &Settings.LayerSelectedColor[N-1] } static int show_help = 0; static int show_version = 0; static int show_copyright = 0; static int show_defaults = 0; static int show_actions = 0; static int do_dump_actions = 0; static char *grid_units; static Increments increment_mm = { 0 }; static Increments increment_mil = { 0 }; void save_increments (const Increments *mm, const Increments *mil) { memcpy (&increment_mm, mm, sizeof (*mm)); memcpy (&increment_mil, mil, sizeof (*mil)); } HID_Attribute main_attribute_list[] = { /* %start-doc options "1 General Options" @ftable @code @item --help Show help on command line options. @end ftable %end-doc */ {"help", "Show help on command line options", HID_Boolean, 0, 0, {0, 0, 0}, 0, &show_help}, /* %start-doc options "1 General Options" @ftable @code @item --version Show version. @end ftable %end-doc */ {"version", "Show version", HID_Boolean, 0, 0, {0, 0, 0}, 0, &show_version}, /* %start-doc options "1 General Options" @ftable @code @item --verbose Be verbose on stdout. @end ftable %end-doc */ {"verbose", "Be verbose on stdout", HID_Boolean, 0, 0, {0, 0, 0}, 0, &Settings.verbose}, /* %start-doc options "1 General Options" @ftable @code @item --copyright Show copyright. @end ftable %end-doc */ {"copyright", "Show Copyright", HID_Boolean, 0, 0, {0, 0, 0}, 0, &show_copyright}, /* %start-doc options "1 General Options" @ftable @code @item --show-defaults Show option defaults. @end ftable %end-doc */ {"show-defaults", "Show option defaults", HID_Boolean, 0, 0, {0, 0, 0}, 0, &show_defaults}, /* %start-doc options "1 General Options" @ftable @code @item --show-actions Show available actions and exit. @end ftable %end-doc */ {"show-actions", "Show available actions", HID_Boolean, 0, 0, {0, 0, 0}, 0, &show_actions}, /* %start-doc options "1 General Options" @ftable @code @item --dump-actions Dump actions (for documentation). @end ftable %end-doc */ {"dump-actions", "Dump actions (for documentation)", HID_Boolean, 0, 0, {0, 0, 0}, 0, &do_dump_actions}, /* %start-doc options "1 General Options" @ftable @code @item --grid-units-mm Set default grid units. Can be mm or mil. Defaults to mil. @end ftable %end-doc */ {"grid-units", "Default grid units (mm|mil)", HID_String, 0, 0, {0, "mil", 0}, 0, &grid_units}, /* %start-doc options "1 General Options" @ftable @code @item --clear-increment-mm Set default clear increment (amount to change when user presses k or K) when user is using a metric grid unit. @end ftable %end-doc */ {"clear-increment-mm", "Default clear increment amount (metric)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mm.clear}, /* %start-doc options "1 General Options" @ftable @code @item --grid-increment-mm Set default grid increment (amount to change when user presses g or G) when user is using a metric grid unit. @end ftable %end-doc */ {"grid-increment-mm", "Default grid increment amount (metric)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mm.grid}, /* %start-doc options "1 General Options" @ftable @code @item --line-increment-mm Set default line increment (amount to change when user presses l or L) when user is using a metric grid unit. @end ftable %end-doc */ {"line-increment-mm", "Default line increment amount (metric)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mm.line}, /* %start-doc options "1 General Options" @ftable @code @item --size-increment-mm Set default size increment (amount to change when user presses s or S) when user is using a metric grid unit. @end ftable %end-doc */ {"size-increment-mm", "Default size increment amount (metric)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mm.size}, /* %start-doc options "1 General Options" @ftable @code @item --clear-increment-mil Set default clear increment (amount to change when user presses k or K) when user is using an imperial grid unit. @end ftable %end-doc */ {"clear-increment-mil", "Default clear increment amount (imperial)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mil.clear}, /* %start-doc options "1 General Options" @ftable @code @item --grid-increment-mil Set default grid increment (amount to change when user presses g or G) when user is using a imperial grid unit. @end ftable %end-doc */ {"grid-increment-mil", "Default grid increment amount (imperial)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mil.grid}, /* %start-doc options "1 General Options" @ftable @code @item --line-increment-mil Set default line increment (amount to change when user presses l or L) when user is using a imperial grid unit. @end ftable %end-doc */ {"line-increment-mil", "Default line increment amount (imperial)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mil.line}, /* %start-doc options "1 General Options" @ftable @code @item --size-increment-mil Set default size increment (amount to change when user presses s or S) when user is using a imperial grid unit. @end ftable %end-doc */ {"size-increment-mil", "Default size increment amount (imperial)", HID_Coord, 0, 0, {0, 0, 0}, 0, &increment_mil.size}, /* %start-doc options "3 Colors" @ftable @code @item --black-color Color value for black. Default: @samp{#000000} @end ftable %end-doc */ COLOR (BlackColor, "#000000", "black-color", "color value of 'black'"), /* %start-doc options "3 Colors" @ftable @code @item --black-color Color value for white. Default: @samp{#ffffff} @end ftable %end-doc */ COLOR (WhiteColor, "#ffffff", "white-color", "color value of 'white'"), /* %start-doc options "3 Colors" @ftable @code @item --background-color Background color of the canvas. Default: @samp{#e5e5e5} @end ftable %end-doc */ COLOR (BackgroundColor, "#e5e5e5", "background-color", "color for background"), /* %start-doc options "3 Colors" @ftable @code @item --crosshair-color Color of the crosshair. Default: @samp{#ff0000} @end ftable %end-doc */ COLOR (CrosshairColor, "#ff0000", "crosshair-color", "color for the crosshair"), /* %start-doc options "3 Colors" @ftable @code @item --cross-color Color of the cross. Default: @samp{#cdcd00} @end ftable %end-doc */ COLOR (CrossColor, "#cdcd00", "cross-color", "color of the cross"), /* %start-doc options "3 Colors" @ftable @code @item --via-color Color of vias. Default: @samp{#7f7f7f} @end ftable %end-doc */ COLOR (ViaColor, "#7f7f7f", "via-color", "color of vias"), /* %start-doc options "3 Colors" @ftable @code @item --via-selected-color Color of selected vias. Default: @samp{#00ffff} @end ftable %end-doc */ COLOR (ViaSelectedColor, "#00ffff", "via-selected-color", "color for selected vias"), /* %start-doc options "3 Colors" @ftable @code @item --pin-color Color of pins. Default: @samp{#4d4d4d} @end ftable %end-doc */ COLOR (PinColor, "#4d4d4d", "pin-color", "color of pins"), /* %start-doc options "3 Colors" @ftable @code @item --pin-selected-color Color of selected pins. Default: @samp{#00ffff} @end ftable %end-doc */ COLOR (PinSelectedColor, "#00ffff", "pin-selected-color", "color of selected pins"), /* %start-doc options "3 Colors" @ftable @code @item --pin-name-color Color of pin names and pin numbers. Default: @samp{#ff0000} @end ftable %end-doc */ COLOR (PinNameColor, "#ff0000", "pin-name-color", "color for pin names and pin numbers"), /* %start-doc options "3 Colors" @ftable @code @item --element-color Color of components. Default: @samp{#000000} @end ftable %end-doc */ COLOR (ElementColor, "#000000", "element-color", "color of components"), /* %start-doc options "3 Colors" @ftable @code @item --rat-color Color of ratlines. Default: @samp{#b8860b} @end ftable %end-doc */ COLOR (RatColor, "#b8860b", "rat-color", "color of ratlines"), /* %start-doc options "3 Colors" @ftable @code @item --invisible-objects-color Color of invisible objects. Default: @samp{#cccccc} @end ftable %end-doc */ COLOR (InvisibleObjectsColor, "#cccccc", "invisible-objects-color", "color of invisible objects"), /* %start-doc options "3 Colors" @ftable @code @item --invisible-mark-color Color of invisible marks. Default: @samp{#cccccc} @end ftable %end-doc */ COLOR (InvisibleMarkColor, "#cccccc", "invisible-mark-color", "color of invisible marks"), /* %start-doc options "3 Colors" @ftable @code @item --element-selected-color Color of selected components. Default: @samp{#00ffff} @end ftable %end-doc */ COLOR (ElementSelectedColor, "#00ffff", "element-selected-color", "color of selected components"), /* %start-doc options "3 Colors" @ftable @code @item --rat-selected-color Color of selected rats. Default: @samp{#00ffff} @end ftable %end-doc */ COLOR (RatSelectedColor, "#00ffff", "rat-selected-color", "color of selected rats"), /* %start-doc options "3 Colors" @ftable @code @item --connected-color Color to indicate physical connections. Default: @samp{#00ff00} @end ftable %end-doc */ COLOR (ConnectedColor, "#00ff00", "connected-color", "color to indicate physically connected objects"), /* %start-doc options "3 Colors" @ftable @code @item --found-color Color to indicate logical connections. Default: @samp{#ff00ff} @end ftable %end-doc */ COLOR (FoundColor, "#ff00ff", "found-color", "color to indicate logically connected objects"), /* %start-doc options "3 Colors" @ftable @code @item --off-limit-color Color of off-canvas area. Default: @samp{#cccccc} @end ftable %end-doc */ COLOR (OffLimitColor, "#cccccc", "off-limit-color", "color of off-canvas area"), /* %start-doc options "3 Colors" @ftable @code @item --grid-color Color of the grid. Default: @samp{#ff0000} @end ftable %end-doc */ COLOR (GridColor, "#ff0000", "grid-color", "color of the grid"), /* %start-doc options "3 Colors" @ftable @code @item --layer-color- Color of layer @code{}, where @code{} is an integer from 1 to 16. @end ftable %end-doc */ LAYERCOLOR (1, "#8b2323"), LAYERCOLOR (2, "#3a5fcd"), LAYERCOLOR (3, "#104e8b"), LAYERCOLOR (4, "#cd3700"), LAYERCOLOR (5, "#548b54"), LAYERCOLOR (6, "#8b7355"), LAYERCOLOR (7, "#00868b"), LAYERCOLOR (8, "#228b22"), LAYERCOLOR (9, "#8b2323"), LAYERCOLOR (10, "#3a5fcd"), LAYERCOLOR (11, "#104e8b"), LAYERCOLOR (12, "#cd3700"), LAYERCOLOR (13, "#548b54"), LAYERCOLOR (14, "#8b7355"), LAYERCOLOR (15, "#00868b"), LAYERCOLOR (16, "#228b22"), /* %start-doc options "3 Colors" @ftable @code @item --layer-selected-color- Color of layer @code{}, when selected. @code{} is an integer from 1 to 16. @end ftable %end-doc */ LAYERSELCOLOR (1), LAYERSELCOLOR (2), LAYERSELCOLOR (3), LAYERSELCOLOR (4), LAYERSELCOLOR (5), LAYERSELCOLOR (6), LAYERSELCOLOR (7), LAYERSELCOLOR (8), LAYERSELCOLOR (9), LAYERSELCOLOR (10), LAYERSELCOLOR (11), LAYERSELCOLOR (12), LAYERSELCOLOR (13), LAYERSELCOLOR (14), LAYERSELCOLOR (15), LAYERSELCOLOR (16), /* %start-doc options "3 Colors" @ftable @code @item --warn-color Color of offending objects during DRC. Default value is @code{"#ff8000"} @end ftable %end-doc */ COLOR (WarnColor, "#ff8000", "warn-color", "color of offending objects during DRC"), /* %start-doc options "3 Colors" @ftable @code @item --mask-color Color of the mask layer. Default value is @code{"#ff0000"} @end ftable %end-doc */ COLOR (MaskColor, "#ff0000", "mask-color", "color for solder mask"), /* %start-doc options "5 Sizes" All parameters should be given with an unit. If no unit is given, 1/100 mil (cmil) will be used. Write units without space to the number like @code{3mm}, not @code{3 mm}. Valid Units are: @table @samp @item km Kilometer @item m Meter @item cm Centimeter @item mm Millimeter @item um Micrometer @item nm Nanometer @item in Inch (1in = 0.0254m) @item mil Mil (1000mil = 1in) @item cmil Centimil (1/100 mil) @end table @ftable @code @item --via-thickness Default diameter of vias. Default value is @code{60mil}. @end ftable %end-doc */ CSET (ViaThickness, MIL_TO_COORD(60), "via-thickness", "default diameter of vias in 1/100 mil"), /* %start-doc options "5 Sizes" @ftable @code @item --via-drilling-hole Default diameter of holes. Default value is @code{28mil}. @end ftable %end-doc */ CSET (ViaDrillingHole, MIL_TO_COORD(28), "via-drilling-hole", "default diameter of holes"), /* %start-doc options "5 Sizes" @ftable @code @item --via-solder-mask-clerance Default soldermask clearance around vias. Default value is @code{0mil}. @end ftable %end-doc */ CSET (ViaMaskAperture, MIL_TO_COORD(0), "via-solder-mask-aperture", "default solder mask aperture for vias"), /* %start-doc options "5 Sizes" @ftable @code @item --line-thickness Default thickness of new lines. Default value is @code{10mil}. @end ftable %end-doc */ CSET (LineThickness, MIL_TO_COORD(10), "line-thickness", "initial thickness of new lines"), /* %start-doc options "5 Sizes" @ftable @code @item --rat-thickness Thickness of rats. If no unit is given, PCB units are assumed (i.e. 100 means "1 nm"). This option allows for a special unit @code{px} which sets the rat thickness to a fixed value in terms of screen pixels. Maximum fixed thickness is 100px. Minimum saling rat thickness is 101nm. Default value is @code{10mil}. @end ftable %end-doc */ CSET (RatThickness, MIL_TO_COORD(10), "rat-thickness", "thickness of rat lines"), /* %start-doc options "5 Sizes" @ftable @code @item --keepaway Default minimum distance between a track and adjacent copper. Default value is @code{10mil}. @end ftable %end-doc */ CSET (Keepaway, MIL_TO_COORD(10), "keepaway", "minimum distance between adjacent copper"), /* %start-doc options "5 Sizes" @ftable @code @item --default-PCB-width Default width of the canvas. Default value is @code{6000mil}. @end ftable %end-doc */ CSET (MaxWidth, MIL_TO_COORD(6000), "default-PCB-width", "default width of the canvas"), /* %start-doc options "5 Sizes" @ftable @code @item --default-PCB-height Default height of the canvas. Default value is @code{5000mil}. @end ftable %end-doc */ CSET (MaxHeight, MIL_TO_COORD(5000), "default-PCB-height", "default height of the canvas"), /* %start-doc options "5 Sizes" @ftable @code @item --text-scale Default text scale. This value is in percent. Default value is @code{100}. @end ftable %end-doc */ ISET (TextScale, 100, "text-scale", "default text scale in percent"), /* %start-doc options "5 Sizes" @ftable @code @item --alignment-distance Specifies the distance between the board outline and alignment targets. Default value is @code{2mil}. @end ftable %end-doc */ CSET (AlignmentDistance, MIL_TO_COORD(2), "alignment-distance", "distance between the boards outline and alignment targets"), /* %start-doc options "7 DRC Options" All parameters should be given with an unit. If no unit is given, 1/100 mil (cmil) will be used for backward compability. Valid units are given in section @ref{Sizes}. %end-doc */ /* %start-doc options "7 DRC Options" @ftable @code @item --bloat Minimum spacing. Default value is @code{10mil}. @end ftable %end-doc */ CSET (Bloat, MIL_TO_COORD(10), "bloat", "DRC minimum spacing in 1/100 mil"), /* %start-doc options "7 DRC Options" @ftable @code @item --shrink Minimum touching overlap. Default value is @code{10mil}. @end ftable %end-doc */ CSET (Shrink, MIL_TO_COORD(10), "shrink", "DRC minimum overlap in 1/100 mils"), /* %start-doc options "7 DRC Options" @ftable @code @item --min-width Minimum width of copper. Default value is @code{10mil}. @end ftable %end-doc */ CSET (minWid, MIL_TO_COORD(10), "min-width", "DRC minimum copper spacing"), /* %start-doc options "7 DRC Options" @ftable @code @item --min-silk Minimum width of lines in silk. Default value is @code{10mil}. @end ftable %end-doc */ CSET (minSlk, MIL_TO_COORD(10), "min-silk", "DRC minimum silk width"), /* %start-doc options "7 DRC Options" @ftable @code @item --min-drill Minimum diameter of holes. Default value is @code{15mil}. @end ftable %end-doc */ CSET (minDrill, MIL_TO_COORD(15), "min-drill", "DRC minimum drill diameter"), /* %start-doc options "7 DRC Options" @ftable @code @item --min-ring Minimum width of annular ring. Default value is @code{10mil}. @end ftable %end-doc */ CSET (minRing, MIL_TO_COORD(10), "min-ring", "DRC minimum annular ring"), /* %start-doc options "5 Sizes" @ftable @code @item --grid Initial grid size. Default value is @code{10mil}. @end ftable %end-doc */ CSET (Grid, MIL_TO_COORD(10), "grid", "Initial grid size in 1/100 mil"), /* %start-doc options "5 Sizes" @ftable @code @item --minimum polygon area Minimum polygon area. @end ftable %end-doc */ RSET (IsleArea, MIL_TO_COORD(100) * MIL_TO_COORD(100), "minimum polygon area", 0), /* %start-doc options "5 Sizes" @ftable @code @item --paste-adjust Adjust pad thickness in paste layer. Default value is @code{0}. Shrinking the pads is done with a negative amount. Example: @example pcb -x gerber --paste-adjust -0.07mm filename.pcb @end example @end ftable %end-doc */ CSET (PasteAdjust, MIL_TO_COORD(0), "paste-adjust", "Adjustment to pad thickness in paste layer in 1/100 mil"), /* %start-doc options "1 General Options" @ftable @code @item --backup-interval Time between automatic backups in seconds. Set to @code{0} to disable. The default value is @code{60}. @end ftable %end-doc */ ISET (BackupInterval, 60, "backup-interval", "Time between automatic backups in seconds. Set to 0 to disable"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-1 Name of the 1st Layer. Default is @code{"top"}. @end ftable %end-doc */ LAYERNAME (1, "top"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-2 Name of the 2nd Layer. Default is @code{"ground"}. @end ftable %end-doc */ LAYERNAME (2, "ground"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-3 Name of the 3nd Layer. Default is @code{"signal2"}. @end ftable %end-doc */ LAYERNAME (3, "signal2"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-4 Name of the 4rd Layer. Default is @code{"signal3"}. @end ftable %end-doc */ LAYERNAME (4, "signal3"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-5 Name of the 5rd Layer. Default is @code{"power"}. @end ftable %end-doc */ LAYERNAME (5, "power"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-6 Name of the 6rd Layer. Default is @code{"bottom"}. @end ftable %end-doc */ LAYERNAME (6, "bottom"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-7 Name of the 7rd Layer. Default is @code{"outline"}. @end ftable %end-doc */ LAYERNAME (7, "outline"), /* %start-doc options "4 Layer Names" @ftable @code @item --layer-name-8 Name of the 8rd Layer. Default is @code{"spare"}. @end ftable %end-doc */ LAYERNAME (8, "spare"), /* %start-doc options "1 General Options" @ftable @code @item --groups Layer group string. Defaults to @code{"1,c:2:3:4:5:6,s:7:8"}. @end ftable %end-doc */ SSET (Groups, "1,c:2:3:4:5:6,s:7:8", "groups", "Layer group string"), /* %start-doc options "6 Commands" pcb uses external commands for input output operations. These commands can be configured at start-up to meet local requirements. The command string may include special sequences @code{%f}, @code{%p} or @code{%a}. These are replaced when the command is called. The sequence @code{%f} is replaced by the file name, @code{%p} gets the path and @code{%a} indicates a package name. %end-doc */ /* %start-doc options "6 Commands" @ftable @code @item --font-command Command to load a font. @end ftable %end-doc */ SSET (FontCommand, "", "font-command", "Command to load a font"), /* %start-doc options "6 Commands" @ftable @code @item --file-command Command to read a file. @end ftable %end-doc */ SSET (FileCommand, "", "file-command", "Command to read a file"), /* %start-doc options "6 Commands" @ftable @code @item --element-command Command to read a footprint. @* Defaults to @code{"M4PATH='%p';export M4PATH;echo 'include(%f)' | m4"} @end ftable %end-doc */ SSET (ElementCommand, "M4PATH='%p';export M4PATH;echo 'include(%f)' | " GNUM4, "element-command", "Command to read a footprint"), /* %start-doc options "6 Commands" @ftable @code @item --print-file Command to print to a file. @end ftable %end-doc */ SSET (PrintFile, "%f.output", "print-file", "Command to print to a file"), /* %start-doc options "6 Commands" @ftable @code @item --lib-command-dir Path to the command that queries the library. @end ftable %end-doc */ SSET (LibraryCommandDir, PCBLIBDIR, "lib-command-dir", "Path to the command that queries the library"), /* %start-doc options "6 Commands" @ftable @code @item --lib-command Command to query the library. @* Defaults to @code{"QueryLibrary.sh '%p' '%f' %a"} @end ftable %end-doc */ SSET (LibraryCommand, "QueryLibrary.sh '%p' '%f' %a", "lib-command", "Command to query the library"), /* %start-doc options "6 Commands" @ftable @code @item --lib-contents-command Command to query the contents of the library. @* Defaults to @code{"ListLibraryContents.sh %p %f"} or, on Windows builds, an empty string (to disable this feature). @end ftable %end-doc */ SSET (LibraryContentsCommand, #ifdef __WIN32__ "", #else "ListLibraryContents.sh '%p' '%f'", #endif "lib-contents-command", "Command to query the contents of the library"), /* %start-doc options "5 Paths" @ftable @code @item --lib-newlib Top level directory for the newlib style library. @end ftable %end-doc */ SSET (LibraryTree, PCBTREEPATH, "lib-newlib", "Top level directory for the newlib style library"), /* %start-doc options "6 Commands" @ftable @code @item --save-command Command to save to a file. @end ftable %end-doc */ SSET (SaveCommand, "", "save-command", "Command to save to a file"), /* %start-doc options "5 Paths" @ftable @code @item --lib-name The default filename for the library. @end ftable %end-doc */ SSET (LibraryFilename, LIBRARYFILENAME, "lib-name", "The default filename for the library"), /* %start-doc options "5 Paths" @ftable @code @item --default-font The name of the default font. @end ftable %end-doc */ SSET (FontFile, "default_font", "default-font", "File name of default font"), /* %start-doc options "1 General Options" @ftable @code @item --route-styles A string that defines the route styles. Parameters are (in order): line width, via hole size, via ring size, clearance, solder mask clearance. The units are cmils. Defaults to @* @code{"Signal,1000,3600,2000,1000,0:Power,2500,6000,3500,1000,0 :Fat,4000,6000,3500,1000,0:Skinny,600,2402,1181,600,0"} @end ftable %end-doc */ SSET (Routes, "Signal,1000,3600,2000,1000,0:Power,2500,6000,3500,1000,0" ":Fat,4000,6000,3500,1000,0:Skinny,600,2402,1181,600,0", "route-styles", "A string that defines the route styles"), /* %start-doc options "5 Paths" @ftable @code @item --file-path A colon separated list of directories or commands (starts with '|'). The path is passed to the program specified in @option{--file-command} together with the selected filename. @end ftable %end-doc */ SSET (FilePath, "", "file-path", 0), /* %start-doc options "6 Commands" @ftable @code @item --rat-command Command for reading a netlist. Sequence @code{%f} is replaced by the netlist filename. @end ftable %end-doc */ SSET (RatCommand, "", "rat-command", "Command for reading a netlist"), /* %start-doc options "5 Paths" @ftable @code @item --font-path A colon separated list of directories to search the default font. Defaults to the default library path. @end ftable %end-doc */ SSET (FontPath, PCBLIBPATH, "font-path", "Colon separated list of directories to search the default font"), /* %start-doc options "1 General Options" @ftable @code @item --element-path A colon separated list of directories or commands (starts with '|'). The path is passed to the program specified in @option{--element-command}. @end ftable %end-doc */ SSET(ElementPath, PCBLIBPATH, "element-path", "A colon separated list of directories or commands (starts with '|')"), /* %start-doc options "5 Paths" @ftable @code @item --lib-path A colon separated list of directories that will be passed to the commands specified by @option{--element-command} and @option{--element-contents-command}. @end ftable %end-doc */ SSET (LibraryPath, PCBLIBPATH, "lib-path", "A colon separated list of directories"), /* %start-doc options "1 General Options" @ftable @code @item --action-script If set, this file is executed at startup. @end ftable %end-doc */ SSET (ScriptFilename, 0, "action-script", "If set, this file is executed at startup"), /* %start-doc options "1 General Options" @ftable @code @item --action-string If set, this string of actions is executed at startup. @end ftable %end-doc */ SSET (ActionString, 0, "action-string", "If set, this is executed at startup"), /* %start-doc options "1 General Options" @ftable @code @item --fab-author Name of author to be put in the Gerber files. @end ftable %end-doc */ SSET (FabAuthor, "", "fab-author", "Name of author to be put in the Gerber files"), /* %start-doc options "1 General Options" @ftable @code @item --layer-stack Initial layer stackup, for setting up an export. A comma separated list of layer names, layer numbers and layer groups. @end ftable %end-doc */ SSET (InitialLayerStack, "", "layer-stack", "Initial layer stackup, for setting up an export."), SSET (MakeProgram, NULL, "make-program", "Sets the name and optionally full path to a make(3) program"), SSET (GnetlistProgram, NULL, "gnetlist", "Sets the name and optionally full path to the gnetlist(3) program"), /* %start-doc options "2 General GUI Options" @ftable @code @item --pinout-offset-x Horizontal offset of the pin number display. Defaults to @code{100mil}. @end ftable %end-doc */ CSET (PinoutOffsetX, MIL_TO_COORD(1), "pinout-offset-x", "Horizontal offset of the pin number display in mil"), /* %start-doc options "2 General GUI Options" @ftable @code @item --pinout-offset-y Vertical offset of the pin number display. Defaults to @code{100mil}. @end ftable %end-doc */ CSET (PinoutOffsetY, MIL_TO_COORD(1), "pinout-offset-y", "Vertical offset of the pin number display in mil"), /* %start-doc options "2 General GUI Options" @ftable @code @item --pinout-text-offset-x Horizontal offset of the pin name display. Defaults to @code{800mil}. @end ftable %end-doc */ CSET (PinoutTextOffsetX, MIL_TO_COORD(8), "pinout-text-offset-x", "Horizontal offset of the pin name display in mil"), /* %start-doc options "2 General GUI Options" @ftable @code @item --pinout-text-offset-y Vertical offset of the pin name display. Defaults to @code{-100mil}. @end ftable %end-doc */ CSET (PinoutTextOffsetY, MIL_TO_COORD(-1), "pinout-text-offset-y", "Vertical offset of the pin name display in mil"), /* %start-doc options "2 General GUI Options" @ftable @code @item --draw-grid If set, draw the grid at start-up. @end ftable %end-doc */ BSET (DrawGrid, 0, "draw-grid", "If set, draw the grid at start-up"), /* %start-doc options "2 General GUI Options" @ftable @code @item --clear-line If set, new lines clear polygons. @end ftable %end-doc */ BSET (ClearLine, 1, "clear-line", "If set, new lines clear polygons"), /* %start-doc options "2 General GUI Options" @ftable @code @item --full-poly If set, new polygons are full ones. @end ftable %end-doc */ BSET (FullPoly, 0, "full-poly", 0), /* %start-doc options "2 General GUI Options" @ftable @code @item --unique-names If set, you will not be permitted to change the name of an component to match that of another component. @end ftable %end-doc */ BSET (UniqueNames, 1, "unique-names", "Prevents identical component names"), /* %start-doc options "2 General GUI Options" @ftable @code @item --snap-pin If set, pin centers and pad end points are treated as additional grid points that the cursor can snap to. @end ftable %end-doc */ BSET (SnapPin, 1, "snap-pin", "If set, the cursor snaps to pads and pin centers"), /* %start-doc options "1 General Options" @ftable @code @item --save-last-command If set, the last user command is saved. @end ftable %end-doc */ BSET (SaveLastCommand, 0, "save-last-command", 0), /* %start-doc options "1 General Options" @ftable @code @item --save-in-tmp If set, all data which would otherwise be lost are saved in a temporary file @file{/tmp/PCB.%i.save} . Sequence @samp{%i} is replaced by the process ID. @end ftable %end-doc */ BSET (SaveInTMP, 0, "save-in-tmp", "When set, all data which would otherwise be lost are saved in /tmp"), /* %start-doc options "1 General Options" @ftable @code @item --save-metric-only If set, save pcb files using only mm unit suffix rather than 'smart' mil/mm. @end ftable %end-doc */ BSET (SaveMetricOnly, 0, "save-metric-only", "If set, save pcb files using only mm unit suffix rather than 'smart' mil/mm."), /* %start-doc options "2 General GUI Options" @ftable @code @item --all-direction-lines Allow all directions, when drawing new lines. @end ftable %end-doc */ BSET (AllDirectionLines, 0, "all-direction-lines", "Allow all directions, when drawing new lines"), /* %start-doc options "2 General GUI Options" @ftable @code @item --show-number Pinout shows number. @end ftable %end-doc */ BSET (ShowNumber, 0, "show-number", "Pinout shows number"), /* %start-doc options "1 General Options" @ftable @code @item --reset-after-element If set, all found connections are reset before a new component is scanned. @end ftable %end-doc */ BSET (ResetAfterElement, 1, "reset-after-element", "If set, all found connections are reset before a new component is scanned"), /* %start-doc options "1 General Options" @ftable @code @item --auto-buried-vias Enables automatically created vias (during line moves and layer switch) to be buriad/blind vias @end ftable %end-doc */ BSET (AutoBuriedVias, 0, "auto-buried-vias", "Enables automatically created vias to be buriad/blind vias"), /* %start-doc options "1 General Options" @ftable @code @item --ring-bell-finished Execute the bell command when all rats are routed. @end ftable %end-doc */ BSET (RingBellWhenFinished, 0, "ring-bell-finished", "Execute the bell command when all rats are routed"), }; REGISTER_ATTRIBUTES (main_attribute_list) /* ---------------------------------------------------------------------- * post-process settings. */ static void settings_post_process () { char *tmps; if (Settings.LibraryCommand != NULL && Settings.LibraryCommand[0] != '\0' && Settings.LibraryCommand[0] != PCB_DIR_SEPARATOR_C && Settings.LibraryCommand[0] != '.') { Settings.LibraryCommand = Concat (Settings.LibraryCommandDir, PCB_DIR_SEPARATOR_S, Settings.LibraryCommand, NULL); } if (Settings.LibraryContentsCommand != NULL && Settings.LibraryContentsCommand[0] != '\0' && Settings.LibraryContentsCommand[0] != PCB_DIR_SEPARATOR_C && Settings.LibraryContentsCommand[0] != '.') { Settings.LibraryContentsCommand = Concat (Settings.LibraryCommandDir, PCB_DIR_SEPARATOR_S, Settings.LibraryContentsCommand, NULL); } if (Settings.LineThickness > MAX_LINESIZE || Settings.LineThickness < MIN_LINESIZE) Settings.LineThickness = MIL_TO_COORD(10); if (Settings.ViaThickness > MAX_PINORVIASIZE || Settings.ViaThickness < MIN_PINORVIASIZE) Settings.ViaThickness = MIL_TO_COORD(40); if (Settings.ViaDrillingHole <= 0) Settings.ViaDrillingHole = DEFAULT_DRILLINGHOLE * Settings.ViaThickness / 100; Settings.MaxWidth = CLAMP (Settings.MaxWidth, MIN_SIZE, MAX_COORD); Settings.MaxHeight = CLAMP (Settings.MaxHeight, MIN_SIZE, MAX_COORD); ParseRouteString (Settings.Routes, &Settings.RouteStyle[0], "cmil"); /* * Make sure we have settings for some various programs we may wish * to call */ if (Settings.MakeProgram == NULL) { tmps = getenv ("PCB_MAKE_PROGRAM"); if (tmps != NULL) Settings.MakeProgram = strdup (tmps); } if (Settings.MakeProgram == NULL) { Settings.MakeProgram = strdup ("make"); } if (Settings.GnetlistProgram == NULL) { tmps = getenv ("PCB_GNETLIST"); if (tmps != NULL) Settings.GnetlistProgram = strdup (tmps); } if (Settings.GnetlistProgram == NULL) { Settings.GnetlistProgram = strdup ("gnetlist"); } if (grid_units) Settings.grid_unit = get_unit_struct (grid_units); if (!grid_units || Settings.grid_unit == NULL) Settings.grid_unit = get_unit_struct ("mil"); copy_nonzero_increments (get_increments_struct (METRIC), &increment_mm); copy_nonzero_increments (get_increments_struct (IMPERIAL), &increment_mil); Settings.increments = get_increments_struct (Settings.grid_unit->family); } /*! * \brief Print help or version messages. */ static void print_version () { printf ("PCB version %s\n", VERSION); exit (0); } /* ---------------------------------------------------------------------- * Figure out the canonical name of the executed program * and fix up the defaults for various paths */ char *bindir = NULL; char *exec_prefix = NULL; char *pcblibdir = NULL; char *pcblibpath = NULL; char *pcbtreedir = NULL; char *pcbtreepath = NULL; char *homedir = NULL; /*! * \brief See if argv0 has enough of a path to let lrealpath give the * real path. * * This should be the case if you invoke pcb with something like * /usr/local/bin/pcb or ./pcb or ./foo/pcb but if you just use pcb and * it exists in your path, you'll just get back pcb again. */ static void InitPaths (char *argv0) { size_t l; int i; int haspath; char *t1, *t2; int found_bindir = 0; haspath = 0; for (i = 0; i < strlen (argv0) ; i++) { if (argv0[i] == PCB_DIR_SEPARATOR_C) haspath = 1; } #ifdef DEBUG printf ("InitPaths (%s): haspath = %d\n", argv0, haspath); #endif if (haspath) { bindir = strdup (lrealpath (argv0)); found_bindir = 1; } else { char *path, *p, *tmps; struct stat sb; int r; tmps = getenv ("PATH"); if (tmps != NULL) { path = strdup (tmps); /* search through the font path for a font file */ for (p = strtok (path, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER)) { #ifdef DEBUG printf ("Looking for %s in %s\n", argv0, p); #endif if ( (tmps = (char *)malloc ( (strlen (argv0) + strlen (p) + 2) * sizeof (char))) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (tmps, "%s%s%s", p, PCB_DIR_SEPARATOR_S, argv0); r = stat (tmps, &sb); if (r == 0) { #ifdef DEBUG printf ("Found it: \"%s\"\n", tmps); #endif bindir = lrealpath (tmps); found_bindir = 1; free (tmps); break; } free (tmps); } free (path); } } #ifdef DEBUG printf ("InitPaths(): bindir = \"%s\"\n", bindir); #endif if (found_bindir) { /* strip off the executible name leaving only the path */ t2 = NULL; t1 = strchr (bindir, PCB_DIR_SEPARATOR_C); while (t1 != NULL && *t1 != '\0') { t2 = t1; t1 = strchr (t2 + 1, PCB_DIR_SEPARATOR_C); } if (t2 != NULL) *t2 = '\0'; #ifdef DEBUG printf ("After stripping off the executible name, we found\n"); printf ("bindir = \"%s\"\n", bindir); #endif } else { /* we have failed to find out anything from argv[0] so fall back to the original * install prefix */ bindir = strdup (BINDIR); } /* now find the path to exec_prefix */ l = strlen (bindir) + 1 + strlen (BINDIR_TO_EXECPREFIX) + 1; if ( (exec_prefix = (char *) malloc (l * sizeof (char) )) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (exec_prefix, "%s%s%s", bindir, PCB_DIR_SEPARATOR_S, BINDIR_TO_EXECPREFIX); /* now find the path to PCBLIBDIR */ l = strlen (bindir) + 1 + strlen (BINDIR_TO_PCBLIBDIR) + 1; if ( (pcblibdir = (char *) malloc (l * sizeof (char) )) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (pcblibdir, "%s%s%s", bindir, PCB_DIR_SEPARATOR_S, BINDIR_TO_PCBLIBDIR); /* and the path to PCBTREEDIR */ l = strlen (bindir) + 1 + strlen (BINDIR_TO_PCBTREEDIR) + 1; if ( (pcbtreedir = (char *) malloc (l * sizeof (char) )) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (pcbtreedir, "%s%s%s", bindir, PCB_DIR_SEPARATOR_S, BINDIR_TO_PCBTREEDIR); /* and the search path including PCBLIBDIR */ l = strlen (pcblibdir) + 3; if ( (pcblibpath = (char *) malloc (l * sizeof (char) )) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (pcblibpath, ".%s%s", PCB_PATH_DELIMETER, pcblibdir); /* and the newlib search path */ l = strlen (pcblibdir) + 1 + strlen (pcbtreedir) + strlen ("pcblib-newlib") + 2; if ( (pcbtreepath = (char *) malloc (l * sizeof (char) )) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (pcbtreepath, "%s%s%s%spcblib-newlib", pcbtreedir, PCB_PATH_DELIMETER, pcblibdir, PCB_DIR_SEPARATOR_S); #ifdef DEBUG printf ("bindir = %s\n", bindir); printf ("pcblibdir = %s\n", pcblibdir); printf ("pcblibpath = %s\n", pcblibpath); printf ("pcbtreedir = %s\n", pcbtreedir); printf ("pcbtreepath = %s\n", pcbtreepath); #endif l = sizeof (main_attribute_list) / sizeof (main_attribute_list[0]); for (i = 0; i < l ; i++) { if (NSTRCMP (main_attribute_list[i].name, "lib-command-dir") == 0) { main_attribute_list[i].default_val.str_value = pcblibdir; } if ( (NSTRCMP (main_attribute_list[i].name, "font-path") == 0) || (NSTRCMP (main_attribute_list[i].name, "element-path") == 0) || (NSTRCMP (main_attribute_list[i].name, "lib-path") == 0) ) { main_attribute_list[i].default_val.str_value = pcblibpath; } if (NSTRCMP (main_attribute_list[i].name, "lib-newlib") == 0) { main_attribute_list[i].default_val.str_value = pcbtreepath; } } { char *tmps; tmps = getenv ("HOME"); if (tmps == NULL) { tmps = getenv ("USERPROFILE"); } if (tmps != NULL) { homedir = strdup (tmps); } else { homedir = NULL; } } } /* ---------------------------------------------------------------------- * main program */ char *program_name = 0; char *program_basename = 0; char *program_directory = 0; #include "dolists.h" /*! * \brief Free up memory allocated to the PCB. * * Why bother when we're about to exit ?\n * Because it removes some false positives from heap bug detectors such * as lib dmalloc. */ void pcb_main_uninit (void) { if (gui->uninit != NULL) gui->uninit (gui); hid_uninit (); UninitBuffers (); FreePCBMemory (PCB); free (PCB); PCB = NULL; /*! * \warning Please do not free the below variables like: * \code for (i = 0; i < MAX_LAYER; i++) free (Settings.DefaultLayerName[i]); if (Settings.FontFile != NULL) { free (Settings.FontFile); Settings.FontFile = NULL; } * \endcode * as these are initialized to static strings and freeing them * causes segfaults when terminating the program. */ uninit_strflags_buf (); uninit_strflags_layerlist (); #define free0(ptr) \ do \ { \ if (ptr != NULL) \ { \ free (ptr); \ ptr = 0; \ } \ } while (0) free0 (pcblibdir); free0 (homedir); free0 (bindir); free0 (exec_prefix); free0 (program_directory); free0 (Settings.MakeProgram); free0 (Settings.GnetlistProgram); #undef free0 } /*! * \brief Main program. * * Init application: * * - make program name available for error handlers * - evaluate special options * - initialize toplevel shell and resources * - create an empty PCB with default symbols * - initialize all other widgets * - update screen and get size of drawing area * - evaluate command-line arguments * - register 'call on exit()' function */ int main (int argc, char *argv[]) { int i; #include "core_lists.h" setbuf (stdout, 0); InitPaths (argv[0]); bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); textdomain (GETTEXT_PACKAGE); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); #ifdef ENABLE_NLS setlocale (LC_ALL, ""); setlocale (LC_NUMERIC, "C"); #endif srand ( time(NULL) ); /* Set seed for rand() */ initialize_units(); polygon_init (); hid_init (); hid_load_settings (); program_name = argv[0]; program_basename = strrchr (program_name, PCB_DIR_SEPARATOR_C); if (program_basename) { program_directory = strdup (program_name); *strrchr (program_directory, PCB_DIR_SEPARATOR_C) = 0; program_basename++; } else { program_directory = strdup ("."); program_basename = program_name; } Progname = program_basename; /* Print usage or version if requested. Then exit. */ if (argc > 1 && (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "-?") == 0 || strcmp (argv[1], "--help") == 0)) usage (); if (argc > 1 && strcmp (argv[1], "-V") == 0) print_version (); /* Export pcb from command line if requested. */ if (argc > 1 && strcmp (argv[1], "-p") == 0) { exporter = gui = hid_find_printer (); argc--; argv++; } else if (argc > 2 && strcmp (argv[1], "-x") == 0) { exporter = gui = hid_find_exporter (argv[2]); argc -= 2; argv += 2; } /* Otherwise start GUI. */ else gui = hid_find_gui (); /* Exit with error if GUI failed to start. */ if (!gui) exit (1); /* Set up layers. */ for (i = 0; i < MAX_LAYER; i++) { char buf[20]; sprintf (buf, "signal%d", i + 1); Settings.DefaultLayerName[i] = strdup (buf); Settings.LayerColor[i] = "#c49350"; Settings.LayerSelectedColor[i] = "#00ffff"; } gui->parse_arguments (&argc, &argv); if (show_help || (argc > 1 && argv[1][0] == '-')) usage (); if (show_version) print_version (); if (show_defaults) print_defaults (); if (show_copyright) copyright (); settings_post_process (); if (show_actions) { print_actions (); exit (0); } if (do_dump_actions) { extern void dump_actions (void); dump_actions (); exit (0); } /* Create a new PCB object in memory */ PCB = CreateNewPCB (); ParseGroupString (Settings.Groups, &PCB->LayerGroups, &PCB->Data->LayerN); /* Add silk layers to newly created PCB */ CreateNewPCBPost (PCB, 1); if (argc > 1) command_line_pcb = argv[1]; ResetStackAndVisibility (); InitCrosshair (); InitHandler (); InitBuffers (); SetMode (ARROW_MODE); if (command_line_pcb) { if (access(command_line_pcb, F_OK)) { /* File does not exist, save the filename and continue with empty board */ PCB->Filename = strdup (command_line_pcb); } else { /* Hard fail if file exists and fails to load */ if (LoadPCB (command_line_pcb)) { fprintf(stderr, "LoadPCB: Failed to load existing file \"%s\". Is it supported PCB file?\n", command_line_pcb); exit(1); } } } if (Settings.InitialLayerStack && Settings.InitialLayerStack[0]) { LayerStringToLayerStack (Settings.InitialLayerStack); } /* This must be called before any other atexit functions * are registered, as it configures an atexit function to * clean up and free various items of allocated memory, * and must be the last last atexit function to run. */ leaky_init (); /* Register a function to be called when the program terminates. * This makes sure that data is saved even if LEX/YACC routines * abort the program. * If the OS doesn't have at least one of them, * the critical sections will be handled by parse_l.l */ atexit (EmergencySave); /* read the library file and display it if it's not empty */ if (!ReadLibraryContents () && Library.MenuN) hid_action ("LibraryChanged"); #ifdef HAVE_LIBSTROKE stroke_init (); #endif if (Settings.ScriptFilename) { Message (_("Executing startup script file %s\n"), Settings.ScriptFilename); hid_actionl ("ExecuteFile", Settings.ScriptFilename, NULL); } if (Settings.ActionString) { Message (_("Executing startup action %s\n"), Settings.ActionString); hid_parse_actions (Settings.ActionString); } if (gui->printer || gui->exporter) { gui->do_export (0); exit (0); } #if HAVE_DBUS pcb_dbus_setup(); #endif EnableAutosave (); #ifdef DEBUG printf ("Settings.LibraryCommandDir = \"%s\"\n", Settings.LibraryCommandDir); printf ("Settings.FontPath = \"%s\"\n", Settings.FontPath); printf ("Settings.ElementPath = \"%s\"\n", Settings.ElementPath); printf ("Settings.LibraryPath = \"%s\"\n", Settings.LibraryPath); printf ("Settings.LibraryTree = \"%s\"\n", Settings.LibraryTree); printf ("Settings.MakeProgram = \"%s\"\n", UNKNOWN (Settings.MakeProgram)); printf ("Settings.GnetlistProgram = \"%s\"\n", UNKNOWN (Settings.GnetlistProgram)); #endif gui->do_export (0); #if HAVE_DBUS pcb_dbus_finish(); #endif pcb_main_uninit (); return (0); } pcb-4.2.2/src/getline.c0000775000076400007640000000661313434555140011615 00000000000000/* getline.c -- Replacement for GNU C library function getline Copyright (C) 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. */ /* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ #ifdef HAVE_CONFIG_H #include #endif #if ! HAVE_GETLINE #include #include #include #include #if STDC_HEADERS #include #else char *malloc (), *realloc (); #endif /* Always add at least this many bytes when extending the buffer. */ #define MIN_CHUNK 64 /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from malloc (or NULL), pointing to *N characters of space. It is realloc'd as necessary. Return the number of characters read (not including the null terminator), or -1 on error or EOF. On a -1 return, the caller should check feof(), if not then errno has been set to indicate the error. */ int getstr (lineptr, n, stream, terminator, offset) char **lineptr; size_t *n; FILE *stream; char terminator; int offset; { int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ char *read_pos; /* Where we're reading into *LINEPTR. */ int ret; if (!lineptr || !n || !stream) { errno = EINVAL; return -1; } if (!*lineptr) { *n = MIN_CHUNK; *lineptr = malloc (*n); if (!*lineptr) { errno = ENOMEM; return -1; } } nchars_avail = *n - offset; read_pos = *lineptr + offset; for (;;) { int save_errno; register int c = getc (stream); save_errno = errno; /* We always want at least one char left in the buffer, since we always (unless we get an error while reading the first char) NUL-terminate the line buffer. */ assert((*lineptr + *n) == (read_pos + nchars_avail)); if (nchars_avail < 2) { if (*n > MIN_CHUNK) *n *= 2; else *n += MIN_CHUNK; nchars_avail = *n + *lineptr - read_pos; *lineptr = realloc (*lineptr, *n); if (!*lineptr) { errno = ENOMEM; return -1; } read_pos = *n - nchars_avail + *lineptr; assert((*lineptr + *n) == (read_pos + nchars_avail)); } if (ferror (stream)) { /* Might like to return partial line, but there is no place for us to store errno. And we don't want to just lose errno. */ errno = save_errno; return -1; } if (c == EOF) { /* Return partial line, if any. */ if (read_pos == *lineptr) return -1; else break; } *read_pos++ = c; nchars_avail--; if (c == terminator) /* Return the line. */ break; } /* Done - NUL terminate and return the number of chars read. */ *read_pos = '\0'; ret = read_pos - (*lineptr + offset); return ret; } int getline (lineptr, n, stream) char **lineptr; size_t *n; FILE *stream; { return getstr (lineptr, n, stream, '\n', 0); } #endif /* !HAVE_GETLINE */ pcb-4.2.2/src/pcb-printf.h0000664000076400007640000001333013533277055012234 00000000000000/*! * \file src/pcb-printf.h * * \brief This file defines a wrapper around sprintf, that * defines new specifiers that take pcb Coord objects * as input. * * There is a fair bit of nasty (repetitious) code in * here, but I feel the gain in clarity for output * code elsewhere in the project will make it worth * it. * * The new specifiers are: \n * %mk output a measure in km \n * %mf output a measure in meters \n * %me output a measure in cm \n * %mm output a measure in mm \n * %mu output a measure in um \n * %mn output a measure in nm \n * %mM output a measure in scaled (mm/um) metric \n * %ml output a measure in mil \n * %mc output a measure in cmil \n * %mt output a measure in 1/10 of mils (for Excellon drill files) \n * %mL output a measure in scaled (mil/in) imperial \n * %ms output a measure in most natural mm/mil units \n * %mS output a measure in most natural scaled units \n * %md output a pair of measures in most natural mm/mil units \n * %mD output a pair of measures in most natural scaled units \n * %m3 output 3 measures in most natural scaled units \n * ... \n * %m9 output 9 measures in most natural scaled units \n * %m* output a measure with unit given as an additional * const char* parameter \n * %m+ accepts an e_allow parameter that masks all subsequent * "natural" (S/D/3/.../9) specifiers to only use certain * units \n * %mr output a measure in a unit readable by parse_l.l * (this will always append a unit suffix) \n * %ma output an angle in degrees (expects degrees) * * These accept the usual printf modifiers for %f, as well as \n * $ output a unit suffix after the measure \n * # prevents all scaling for %mS/D/1/.../9 (this should * ONLY be used for debug code since its output exposes * pcb's base units). * ` always use '.' as decimal separator (note that %mr uses * this by default). * * KNOWN ISSUES: \n * No support for %zu size_t printf spec * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2011 Andrew Poelstra * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Andrew Poelstra, 16966 60A Ave, V3S 8X5 Surrey, BC, Canada * asp11@sfu.ca * */ #ifndef PCB_PCB_PRINTF_H #define PCB_PCB_PRINTF_H enum e_allow { NO_PRINT = 0, /* suffixes we can read but not print (i.e., "inch") */ ALLOW_NM = 1, ALLOW_UM = 2, ALLOW_MM = 4, ALLOW_CM = 8, ALLOW_M = 16, ALLOW_KM = 32, ALLOW_CMIL = 1024, ALLOW_DMIL = 2048, ALLOW_MIL = 4096, ALLOW_IN = 8192, ALLOW_METRIC = ALLOW_NM | ALLOW_UM | ALLOW_MM | ALLOW_CM | ALLOW_M | ALLOW_KM, ALLOW_IMPERIAL = ALLOW_CMIL | ALLOW_DMIL | ALLOW_MIL | ALLOW_IN, /* This is all units allowed in parse_l.l */ #if 0 ALLOW_READABLE = ALLOW_NM | ALLOW_UM | ALLOW_MM | ALLOW_M | ALLOW_KM | ALLOW_CMIL | ALLOW_MIL | ALLOW_IN, #else ALLOW_READABLE = ALLOW_MIL | ALLOW_MM, #endif ALLOW_ALL = ~ALLOW_DMIL }; enum e_family { METRIC, IMPERIAL }; enum e_suffix { NO_SUFFIX, /*!< no suffix. */ SUFFIX, /*!< suffix, prefixed with ' '. */ FILE_MODE_NO_SUFFIX, /*!< no suffix, force '.' as decimal. */ FILE_MODE /*!< suffix, force '.' as decimal. */ }; struct unit { int index; /*!< Index into Unit[] list. */ const char *suffix; const char *in_suffix; /*!< internationalized suffix. */ char printf_code; double scale_factor; enum e_family family; enum e_allow allow; int default_prec; /* used for gui spinboxes */ double step_tiny; double step_small; double step_medium; double step_large; double step_huge; /* aliases -- right now we only need 1 ("inch"->"in"), add as needed */ const char *alias[1]; }; struct increments { const char *suffix; /* key g and g value */ Coord grid; Coord grid_min; Coord grid_max; /* key s and s value */ Coord size; Coord size_min; Coord size_max; /* key l and l value */ Coord line; Coord line_min; Coord line_max; /* key k and k value */ Coord clear; Coord clear_min; Coord clear_max; }; void initialize_units(); const Unit *get_unit_struct (const char *suffix); const Unit *get_unit_list (void); int get_n_units (void); double coord_to_unit (const Unit *, Coord); Coord unit_to_coord (const Unit *, double); Increments *get_increments_struct (enum e_family family); void copy_nonzero_increments (Increments *dst, const Increments *src); enum e_allow set_allow_readable(enum e_allow new_mask); int pcb_fprintf(FILE *f, const char *fmt, ...); int pcb_snprintf(char *string, size_t size, const char *fmt, ...); int pcb_printf(const char *fmt, ...); char *pcb_g_strdup_printf(const char *fmt, ...); gchar *pcb_vprintf(const char *fmt, va_list args); #ifdef PCB_UNIT_TEST void pcb_printf_register_tests (); void pcb_printf_test_unit (); void pcb_printf_test_printf (); #endif #endif pcb-4.2.2/src/heap.h0000664000076400007640000000345413434555140011105 00000000000000/*! * \file src/heap.h * * \brief Prototypes for heap routines. * * This file, heap.h, was written and is * * Copyright (c) 2001 C. Scott Ananian * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994,1995,1996 Thomas Nau * * Copyright (C) 1998,1999,2000,2001 harry eaton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * harry eaton, 6697 Buttonhole Ct, Columbia, MD 21044 USA * haceaton@aplcomm.jhuapl.edu */ #ifndef PCB_HEAP_H #define PCB_HEAP_H #include "global.h" /*! * \brief Type of heap costs. */ typedef double cost_t; /*! * \brief What a heap looks like. */ typedef struct heap_struct heap_t; heap_t *heap_create (); void heap_destroy (heap_t ** heap); void heap_free (heap_t * heap, void (*funcfree) (void *)); /* -- mutation -- */ void heap_insert (heap_t * heap, cost_t cost, void *data); void *heap_remove_smallest (heap_t * heap); void *heap_replace (heap_t * heap, cost_t cost, void *data); /* -- interrogation -- */ int heap_is_empty (heap_t * heap); int heap_size (heap_t * heap); #endif /* PCB_HEAP_H */ pcb-4.2.2/src/hid/0000775000076400007640000000000013611113566010634 500000000000000pcb-4.2.2/src/hid/hidint.h0000664000076400007640000000720613533277055012220 00000000000000/*! * \file src/hid/hidint.h * * \brief HID internal interfaces. * * These may ONLY be called from the HID modules, not from the common * PCB code. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2006 DJ Delorie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de */ /* These decode the set_layer index. */ #define SL_TYPE(x) ((x) < 0 ? (x) & 0x0f0 : 0) #define SL_SIDE(x) ((x) & 0x00f) #define SL_MYSIDE(x) ((((x) & SL_BOTTOM_SIDE)!=0) == (SWAP_IDENT != 0)) /*! * \brief Called by the init funcs, used to set up hid_list. */ extern void hid_register_hid (HID * hid); /*! * \brief NULL terminated list of all static HID structures. * * Built by hid_register_hid, used by hid_find_*() and hid_enumerate(). * The order in this list is the same as the order of hid_register_hid * calls. */ extern HID **hid_list; /*! * \brief Count of entries in the above. */ extern int hid_num_hids; /*! * \brief Used to cache color lookups. * * If set is zero, it looks up the name and if found sets val and * returns nonzero. If not found, it returns zero. If set is nonzero, * name/val is added to the cache. */ int hid_cache_color (int set, const char *name, hidval * val, void **cache); typedef struct HID_AttrNode { struct HID_AttrNode *next; HID_Attribute *attributes; int n; } HID_AttrNode; extern HID_AttrNode *hid_attr_nodes; HID_Action *hid_find_action (const char *name); HID_Flag *hid_find_flag (const char *name); /*! * \brief A HID may use this if it does not need command line arguments * in any special format. * * For example, the Lesstif HID needs to use the Xt parser, but the * Postscript HID can use this function. */ void hid_parse_command_line (int *argc, char ***argv); /*! * \brief Use this to temporarily enable all layers, so that they can be * exported even if they're not currently visible. * * save_array must be MAX_ALL_LAYER big. */ void hid_save_and_show_layer_ons (int *save_array); /*! * \brief Use this to restore them. */ void hid_restore_layer_ons (int *save_array); enum File_Name_Style { FNS_fixed, /*!< Files for copper layers are named top, groupN, bottom. */ FNS_single, /*!< Groups with multiple layers are named as above, else the single layer name is used. */ FNS_first, /*!< The name of the first layer in each group is used. */ }; /* Returns a filename base that can be used to output the layer. */ const char *layer_type_to_file_name (int idx, int style); const char *layer_type_to_file_name_ex (int idx, int style, const char *layer_name); /*! * \brief Convenience function that calls the expose callback for the * item, and returns the extents of what was drawn. */ BoxType *hid_get_extents (void *item); void derive_default_filename(const char *pcbfile, HID_Attribute *filename_attrib, const char *suffix, char **memory); pcb-4.2.2/src/hid/png/0000775000076400007640000000000013611113567011421 500000000000000pcb-4.2.2/src/hid/png/png_lists.h0000664000076400007640000000005113611070713013503 00000000000000REGISTER_ATTRIBUTES (png_attribute_list) pcb-4.2.2/src/hid/png/hid.conf0000664000076400007640000000001411660653115012747 00000000000000type=export pcb-4.2.2/src/hid/png/png.h0000664000076400007640000000200613604156111012266 00000000000000/*! * \file src/hid/png/png.h * * \brief Header file for the PNG HID exporter. * * Heavily based on the ps HID written by DJ Delorie. * *
* * PCB, interactive printed circuit board design. * * Copyright (C) 2006 Dan McMahill. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ extern void png_hid_export_to_file (FILE *, HID_Attr_Val *); pcb-4.2.2/src/hid/png/png.c0000664000076400007640000013303613604156111012271 00000000000000/*! * \file src/hid/png/png.c * * \brief PNG HID exporter. * * Heavily based on the ps HID written by DJ Delorie. * *
* * PCB, interactive printed circuit board design. * * Copyright (C) 2006 Dan McMahill. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "global.h" #include "data.h" #include "error.h" #include "misc.h" #include "hid.h" #include "hid_draw.h" #include "../hidint.h" #include "hid/common/hidnogui.h" #include "hid/common/draw_helpers.h" #include "png.h" /* the gd library which makes this all so easy */ #include #include "hid/common/hidinit.h" #ifdef HAVE_LIBDMALLOC #include #endif #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort() static HID png_hid; static HID_DRAW png_graphics; static void *color_cache = NULL; static void *brush_cache = NULL; static double bloat = 0; static double scale = 1; static Coord x_shift = 0; static Coord y_shift = 0; static int show_bottom_side; #define SCALE(w) ((int)round((w)/scale)) #define SCALE_X(x) ((int)round(((x) - x_shift)/scale)) #define SCALE_Y(y) ((int)round(((show_bottom_side ? (PCB->MaxHeight-(y)) : (y)) - y_shift)/scale)) #define SWAP_IF_SOLDER(a,b) do { Coord c; if (show_bottom_side) { c=a; a=b; b=c; }} while (0) /* Used to detect non-trivial outlines */ #define NOT_EDGE_X(x) ((x) != 0 && (x) != PCB->MaxWidth) #define NOT_EDGE_Y(y) ((y) != 0 && (y) != PCB->MaxHeight) #define NOT_EDGE(x,y) (NOT_EDGE_X(x) || NOT_EDGE_Y(y)) static void png_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius); /* The result of a failed gdImageColorAllocate() call */ #define BADC -1 typedef struct color_struct { /* the descriptor used by the gd library */ int c; /* so I can figure out what rgb value c refers to */ unsigned int r, g, b, a; } color_struct; typedef struct hid_gc_struct { HID *me_pointer; EndCapStyle cap; int width; unsigned char r, g, b; color_struct *color; gdImagePtr brush; int is_erase; } hid_gc_struct; static color_struct *black = NULL, *white = NULL; static gdImagePtr im = NULL, master_im, mask_im = NULL; static FILE *f = 0; static int linewidth = -1; static int lastgroup = -1; static gdImagePtr lastbrush = (gdImagePtr)((void *) -1); static int lastcap = -1; static int print_group[MAX_GROUP]; static int print_layer[MAX_ALL_LAYER]; /* For photo-mode we need the following layers as monochrome masks: top soldermask top silk copper layers drill */ #define PHOTO_FLIP_X 1 #define PHOTO_FLIP_Y 2 static int photo_mode, photo_flip; static gdImagePtr photo_copper[MAX_ALL_LAYER]; static gdImagePtr photo_silk, photo_mask, photo_drill, *photo_im; static gdImagePtr photo_outline; static int photo_groups[MAX_ALL_LAYER], photo_ngroups; static int photo_has_inners; static int doing_outline, have_outline; #define FMT_gif "GIF" #define FMT_jpg "JPEG" #define FMT_png "PNG" /* If this table has no elements in it, then we have no reason to register this HID and will refrain from doing so at the end of this file. */ #undef HAVE_SOME_FORMAT static const char *filetypes[] = { #ifdef HAVE_GDIMAGEPNG FMT_png, #define HAVE_SOME_FORMAT 1 #endif #ifdef HAVE_GDIMAGEGIF FMT_gif, #define HAVE_SOME_FORMAT 1 #endif #ifdef HAVE_GDIMAGEJPEG FMT_jpg, #define HAVE_SOME_FORMAT 1 #endif NULL }; static const char *mask_colour_names[] = { "green", "red", "blue", "purple", "black", "white", NULL }; // These values were arrived at through trial and error. // One potential improvement (especially for white) is // to use separate color_structs for the multiplication // and addition parts of the mask math. static const color_struct mask_colours[] = { #define MASK_COLOUR_GREEN 0 {.r = 60, .g = 160, .b = 60}, #define MASK_COLOUR_RED 1 {.r = 140, .g = 25, .b = 25}, #define MASK_COLOUR_BLUE 2 {.r = 50, .g = 50, .b = 160}, #define MASK_COLOUR_PURPLE 3 {.r = 60, .g = 20, .b = 70}, #define MASK_COLOUR_BLACK 4 {.r = 20, .g = 20, .b = 20}, #define MASK_COLOUR_WHITE 5 {.r = 167, .g = 230, .b = 162}, // <-- needs improvement over FR4 {} }; static const char *plating_type_names[] = { #define PLATING_TIN 0 "tinned", #define PLATING_GOLD 1 "gold", #define PLATING_SILVER 2 "silver", #define PLATING_COPPER 3 "copper", NULL }; static const char *silk_colour_names[] = { "white", "black", "yellow", NULL }; static const color_struct silk_colours[] = { #define SILK_COLOUR_WHITE 0 {.r = 224, .g = 224, .b = 224}, #define SILK_COLOUR_BLACK 1 {.r = 14, .g = 14, .b = 14}, #define SILK_COLOUR_YELLOW 2 {.r = 185, .g = 185, .b = 10}, {} }; static const color_struct silk_top_shadow = {.r = 21, .g = 21, .b = 21}; static const color_struct silk_bottom_shadow = {.r = 14, .g = 14, .b = 14}; HID_Attribute png_attribute_list[] = { /* other HIDs expect this to be first. */ /* %start-doc options "93 PNG Options" @ftable @code @item --outfile Name of the file to be exported to. Parameter @code{} can include a path. @end ftable %end-doc */ {"outfile", "Graphics output file", HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_pngfile 0 /* %start-doc options "93 PNG Options" @ftable @code @item --dpi Scale factor in pixels/inch. Set to 0 to scale to size specified in the layout. @end ftable %end-doc */ {"dpi", "Scale factor (pixels/inch). 0 to scale to specified size", HID_Integer, 0, 10000, {100, 0, 0}, 0, 0}, #define HA_dpi 1 /* %start-doc options "93 PNG Options" @ftable @code @item --x-max Width of the png image in pixels. No constraint, when set to 0. @end ftable %end-doc */ {"x-max", "Maximum width (pixels). 0 to not constrain", HID_Integer, 0, 10000, {0, 0, 0}, 0, 0}, #define HA_xmax 2 /* %start-doc options "93 PNG Options" @ftable @code @item --y-max Height of the png output in pixels. No constraint, when set to 0. @end ftable %end-doc */ {"y-max", "Maximum height (pixels). 0 to not constrain", HID_Integer, 0, 10000, {0, 0, 0}, 0, 0}, #define HA_ymax 3 /* %start-doc options "93 PNG Options" @ftable @code @item --xy-max Maximum width and height of the PNG output in pixels. No constraint, when set to 0. @end ftable %end-doc */ {"xy-max", "Maximum width and height (pixels). 0 to not constrain", HID_Integer, 0, 10000, {0, 0, 0}, 0, 0}, #define HA_xymax 4 /* %start-doc options "93 PNG Options" @ftable @code @item --screen-layer-order Export layers in the order shown on screen. @end ftable %end-doc */ {"screen-layer-order", "Export layers in the order shown on screen", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_as_shown 5 /* %start-doc options "93 PNG Options" @ftable @code @item --monochrome Convert output to monochrome. @end ftable %end-doc */ {"monochrome", "Convert to monochrome", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_mono 6 /* %start-doc options "93 PNG Options" @ftable @code @item --only-visible Limit the bounds of the exported PNG image to the visible items. @end ftable %end-doc */ {"only-visible", "Limit the bounds of the PNG image to the visible items", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_only_visible 7 /* %start-doc options "93 PNG Options" @ftable @code @item --use-alpha Make the background and any holes transparent. @end ftable %end-doc */ {"use-alpha", "Make the background and any holes transparent", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_use_alpha 8 /* %start-doc options "93 PNG Options" @ftable @code @item --fill-holes Drill holes in pins/pads are filled, not hollow. @end ftable %end-doc */ {"fill-holes", "Drill holes in pins/pads are filled, not hollow", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_fill_holes 9 /* %start-doc options "93 PNG Options" @ftable @code @item --format File format to be exported. Parameter @code{} can be @samp{PNG}, @samp{GIF}, or @samp{JPEG}. @end ftable %end-doc */ {"format", "Export file format", HID_Enum, 0, 0, {0, 0, 0}, filetypes, 0}, #define HA_filetype 10 /* %start-doc options "93 PNG Options" @ftable @code @item --png-bloat Amount of extra thickness to add to traces, pads, or pin edges. The parameter @samp{} is a number, appended by a dimension @samp{mm}, @samp{mil}, or @samp{pix}. If no dimension is given, the default dimension is 1/100 mil. @end ftable %end-doc */ {"png-bloat", "Amount (in/mm/mil/pix) to add to trace/pad/pin edges (1 = 1/100 mil)", HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_bloat 11 /* %start-doc options "93 PNG Options" @ftable @code @cindex photo-mode @item --photo-mode Export a photo realistic image of the layout. @end ftable %end-doc */ {"photo-mode", "Photo-realistic export mode", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_photo_mode 12 /* %start-doc options "93 PNG Options" @ftable @code @item --photo-flip-x In photo-realistic mode, export the reverse side of the layout. Left-right flip. @end ftable %end-doc */ {"photo-flip-x", "Show reverse side of the board, left-right flip", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_photo_flip_x 13 /* %start-doc options "93 PNG Options" @ftable @code @item --photo-flip-y In photo-realistic mode, export the reverse side of the layout. Up-down flip. @end ftable %end-doc */ {"photo-flip-y", "Show reverse side of the board, up-down flip", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_photo_flip_y 14 /* %start-doc options "93 PNG Options" @ftable @code @cindex photo-mask-colour @item --photo-mask-colour In photo-realistic mode, export the solder mask as this colour. Parameter @code{} can be @samp{green}, @samp{red}, @samp{blue}, @samp{purple}, @samp{black}, or @samp{white}. @end ftable %end-doc */ {"photo-mask-colour", "Colour for the exported colour mask", HID_Enum, 0, 0, {0, 0, 0}, mask_colour_names, 0}, #define HA_photo_mask_colour 15 /* %start-doc options "93 PNG Options" @ftable @code @cindex photo-plating @item --photo-plating In photo-realistic mode, export the exposed copper as though it has this type of plating. Parameter @code{} can be @samp{tinned}, @samp{gold}, @samp{silver}, or @samp{copper}. @end ftable %end-doc */ {"photo-plating", "Type of plating applied to exposed copper in photo-mode", HID_Enum, 0, 0, {0, 0, 0}, plating_type_names, 0}, #define HA_photo_plating 16 /* %start-doc options "93 PNG Options" @ftable @code @cindex photo-silk-colour @item --photo-silk-colour In photo-realistic mode, export the silk screen as this colour. Parameter @code{} can be @samp{white}, @samp{black}, or @samp{yellow}. @end ftable %end-doc */ {"photo-silk-colour", "Colour for the exported colour mask", HID_Enum, 0, 0, {0, 0, 0}, silk_colour_names, 0}, #define HA_photo_silk_colour 17 {"ben-mode", ATTR_UNDOCUMENTED, HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_ben_mode 12 {"ben-flip-x", ATTR_UNDOCUMENTED, HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_ben_flip_x 13 {"ben-flip-y", ATTR_UNDOCUMENTED, HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_ben_flip_y 14 }; #define NUM_OPTIONS (sizeof(png_attribute_list)/sizeof(png_attribute_list[0])) REGISTER_ATTRIBUTES (png_attribute_list) static HID_Attr_Val png_values[NUM_OPTIONS]; static const char *get_file_suffix(void) { const char *result = NULL; const char *fmt; fmt = filetypes[png_attribute_list[HA_filetype].default_val.int_value]; if (fmt == NULL) ; /* Do nothing */ else if (strcmp (fmt, FMT_gif) == 0) result=".gif"; else if (strcmp (fmt, FMT_jpg) == 0) result=".jpg"; else if (strcmp (fmt, FMT_png) == 0) result=".png"; if (result == NULL) { fprintf (stderr, "Error: Invalid graphic file format\n"); result=".???"; } return result; } static HID_Attribute * png_get_export_options (int *n) { static char *last_made_filename = 0; const char *suffix = get_file_suffix(); if (PCB) derive_default_filename (PCB->Filename, &png_attribute_list[HA_pngfile], suffix, &last_made_filename); if (n) *n = NUM_OPTIONS; return png_attribute_list; } static int top_group, bottom_group; static int layer_stack_sort (const void *va, const void *vb) { int a_layer = *(int *) va; int b_layer = *(int *) vb; int a_group = GetLayerGroupNumberByNumber (a_layer); int b_group = GetLayerGroupNumberByNumber (b_layer); int aside = (a_group == bottom_group ? 0 : a_group == top_group ? 2 : 1); int bside = (b_group == bottom_group ? 0 : b_group == top_group ? 2 : 1); if (bside != aside) return bside - aside; if (b_group != a_group) return b_group - a_group; return b_layer - a_layer; } static const char *filename; static BoxType *bounds; static int in_mono, as_shown, fill_holes; static void parse_bloat (const char *str) { UnitList extra_units = { { "pix", scale, 0 }, { "px", scale, 0 }, { "", 0, 0 } }; if (str == NULL) return; bloat = GetValueEx (str, NULL, NULL, extra_units, ""); } void png_hid_export_to_file (FILE * the_file, HID_Attr_Val * options) { int i; static int saved_layer_stack[MAX_LAYER]; int saved_show_bottom_side; BoxType region; FlagType save_flags; f = the_file; region.X1 = 0; region.Y1 = 0; region.X2 = PCB->MaxWidth; region.Y2 = PCB->MaxHeight; if (options[HA_only_visible].int_value) bounds = GetDataBoundingBox (PCB->Data); else bounds = ®ion; memset (print_group, 0, sizeof (print_group)); memset (print_layer, 0, sizeof (print_layer)); for (i = 0; i < max_copper_layer; i++) { LayerType *layer = PCB->Data->Layer + i; if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN) print_group[GetLayerGroupNumberByNumber (i)] = 1; } print_group[GetLayerGroupNumberBySide (BOTTOM_SIDE)] = 1; print_group[GetLayerGroupNumberBySide (TOP_SIDE)] = 1; for (i = 0; i < max_copper_layer; i++) if (print_group[GetLayerGroupNumberByNumber (i)]) print_layer[i] = 1; memcpy (saved_layer_stack, LayerStack, sizeof (LayerStack)); save_flags = PCB->Flags; saved_show_bottom_side = Settings.ShowBottomSide; as_shown = options[HA_as_shown].int_value; fill_holes = options[HA_fill_holes].int_value; if (!options[HA_as_shown].int_value) { CLEAR_FLAG (SHOWMASKFLAG, PCB); Settings.ShowBottomSide = 0; top_group = GetLayerGroupNumberBySide (TOP_SIDE); bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); qsort (LayerStack, max_copper_layer, sizeof (LayerStack[0]), layer_stack_sort); CLEAR_FLAG(THINDRAWFLAG, PCB); CLEAR_FLAG(THINDRAWPOLYFLAG, PCB); if (photo_mode) { int i, n=0; SET_FLAG (SHOWMASKFLAG, PCB); photo_has_inners = 0; if (top_group < bottom_group) for (i = top_group; i <= bottom_group; i++) { photo_groups[n++] = i; if (i != top_group && i != bottom_group && ! IsLayerGroupEmpty (i)) photo_has_inners = 1; } else for (i = top_group; i >= bottom_group; i--) { photo_groups[n++] = i; if (i != top_group && i != bottom_group && ! IsLayerGroupEmpty (i)) photo_has_inners = 1; } if (!photo_has_inners) { photo_groups[1] = photo_groups[n - 1]; n = 2; } photo_ngroups = n; if (photo_flip) { for (i=0, n=photo_ngroups-1; iFlags = save_flags; Settings.ShowBottomSide = saved_show_bottom_side; } /*! * \brief Clip RGB values. * * Red, Green and Blue values are clipped to a maximum value of 255. */ static void clip (color_struct *dest, color_struct *source) { #define CLIP(var) \ dest->var = source->var; \ if (dest->var > 255) dest->var = 255; \ if (dest->var < 0) dest->var = 0; CLIP (r); CLIP (g); CLIP (b); #undef CLIP } /*! * \brief Blend two colors. * * \param a color. * \param b color. * \param a_amount weighing value for color \c a. * * The weighing value for color \c b is the complement of \c a_amount * ( 1 - a_amount). */ static void blend (color_struct *dest, double a_amount, color_struct *a, color_struct *b) { dest->r = a->r * a_amount + b->r * (1 - a_amount); dest->g = a->g * a_amount + b->g * (1 - a_amount); dest->b = a->b * a_amount + b->b * (1 - a_amount); } /*! * \brief Multiply two colors. */ static void multiply (color_struct *dest, color_struct *a, color_struct *b) { dest->r = (a->r * b->r) / 255; dest->g = (a->g * b->g) / 255; dest->b = (a->b * b->b) / 255; } /*! * \brief Add two colors. * * \param a color. * \param b color. * \param a_amount weighing value for color \c a. * \param b_amount weighing value for color \c b. * * The result is clipped. */ static void add (color_struct *dest, double a_amount, const color_struct *a, double b_amount, const color_struct *b) { dest->r = a->r * a_amount + b->r * b_amount; dest->g = a->g * a_amount + b->g * b_amount; dest->b = a->b * a_amount + b->b * b_amount; clip (dest, dest); } /*! * \brief Subtract two colors. * * \param a color. * \param b color. * \param a_amount weighing value for color \c a. * \param b_amount weighing value for color \c b. * * The result is clipped. */ static void subtract (color_struct *dest, double a_amount, const color_struct *a, double b_amount, const color_struct *b) { dest->r = a->r * a_amount - b->r * b_amount; dest->g = a->g * a_amount - b->g * b_amount; dest->b = a->b * a_amount - b->b * b_amount; clip (dest, dest); } /*! * \brief Store RGB values in a color struct. * * \param dest pointer to a color struct. * \param r Red value. * \param g Green value. * \param b Blue value. */ static void rgb (color_struct *dest, int r, int g, int b) { dest->r = r; dest->g = g; dest->b = b; } static int smshadows[3][3] = { { 1, 20, 1 }, { 10, 0, -10 }, { -1, -20, -1 }, }; static int shadows[5][5] = { { 1, 1, 1, 1, -1 }, { 1, 1, 1, -1, -1 }, { 1, 1, 0, -1, -1 }, { 1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1 }, }; /* black and white are 0 and 1 */ #define TOP_SHADOW 2 #define BOTTOM_SHADOW 3 static void ts_bs (gdImagePtr im) { int x, y, sx, sy, si; for (x=0; x 1) gdImageSetPixel (im, x, y, TOP_SHADOW); else if (si < -1) gdImageSetPixel (im, x, y, BOTTOM_SHADOW); } } } static void ts_bs_sm (gdImagePtr im) { int x, y, sx, sy, si; for (x=0; x 1) gdImageSetPixel (im, x, y, TOP_SHADOW); else if (si < -1) gdImageSetPixel (im, x, y, BOTTOM_SHADOW); } } } static void png_do_export (HID_Attr_Val * options) { int save_ons[MAX_ALL_LAYER]; int i; BoxType *bbox; Coord w, h; Coord xmax, ymax; int dpi; const char *fmt; bool format_error = false; if (color_cache) { free (color_cache); color_cache = NULL; } if (brush_cache) { free (brush_cache); brush_cache = NULL; } if (!options) { png_get_export_options (0); for (i = 0; i < NUM_OPTIONS; i++) png_values[i] = png_attribute_list[i].default_val; options = png_values; } if (options[HA_photo_mode].int_value || options[HA_ben_mode].int_value) { photo_mode = 1; options[HA_mono].int_value = 1; options[HA_as_shown].int_value = 0; memset (photo_copper, 0, sizeof(photo_copper)); photo_silk = photo_mask = photo_drill = 0; photo_outline = 0; if (options[HA_photo_flip_x].int_value || options[HA_ben_flip_x].int_value) photo_flip = PHOTO_FLIP_X; else if (options[HA_photo_flip_y].int_value || options[HA_ben_flip_y].int_value) photo_flip = PHOTO_FLIP_Y; else photo_flip = 0; } else photo_mode = 0; filename = options[HA_pngfile].str_value; if (!filename) filename = "pcb-out.png"; /* figure out width and height of the board */ if (options[HA_only_visible].int_value) { bbox = GetDataBoundingBox (PCB->Data); if (bbox == NULL) { fprintf (stderr, _("ERROR: Unable to determine bounding box limits\n")); fprintf (stderr, _("ERROR: Does the file contain any data?\n")); return; } x_shift = bbox->X1; y_shift = bbox->Y1; h = bbox->Y2 - bbox->Y1; w = bbox->X2 - bbox->X1; } else { x_shift = 0; y_shift = 0; h = PCB->MaxHeight; w = PCB->MaxWidth; } /* * figure out the scale factor we need to make the image * fit in our specified PNG file size */ xmax = ymax = dpi = 0; if (options[HA_dpi].int_value != 0) { dpi = options[HA_dpi].int_value; if (dpi < 0) { fprintf (stderr, "ERROR: dpi may not be < 0\n"); return; } } if (options[HA_xmax].int_value > 0) { xmax = options[HA_xmax].int_value; dpi = 0; } if (options[HA_ymax].int_value > 0) { ymax = options[HA_ymax].int_value; dpi = 0; } if (options[HA_xymax].int_value > 0) { dpi = 0; if (options[HA_xymax].int_value < xmax || xmax == 0) xmax = options[HA_xymax].int_value; if (options[HA_xymax].int_value < ymax || ymax == 0) ymax = options[HA_xymax].int_value; } if (xmax < 0 || ymax < 0) { fprintf (stderr, "ERROR: xmax and ymax may not be < 0\n"); return; } if (dpi > 0) { /* * a scale of 1 means 1 pixel is 1 inch * a scale of 10 means 1 pixel is 10 inches */ scale = round(INCH_TO_COORD(1) / (double) dpi); w = w / scale; h = h / scale; } else if( xmax == 0 && ymax == 0) { fprintf(stderr, "ERROR: You may not set both xmax, ymax," "and xy-max to zero\n"); return; } else { if (ymax == 0 || ( (xmax > 0) && ((w / xmax) > (h / ymax)) ) ) { scale = w / xmax; h = h / scale; w = xmax; } else { scale = h / ymax; w = w / scale; h = ymax; } } im = gdImageCreate (w, h); if (im == NULL) { Message ("%s(): gdImageCreate(%d, %d) returned NULL. Aborting export.\n", __FUNCTION__, w, h); return; } master_im = im; parse_bloat (options[HA_bloat].str_value); /* * Allocate white and black -- the first color allocated * becomes the background color */ white = (color_struct *) malloc (sizeof (color_struct)); white->r = white->g = white->b = 255; if (options[HA_use_alpha].int_value) white->a = 127; else white->a = 0; white->c = gdImageColorAllocateAlpha (im, white->r, white->g, white->b, white->a); if (white->c == BADC) { Message ("%s(): gdImageColorAllocateAlpha() returned NULL. Aborting export.\n", __FUNCTION__); return; } gdImageFilledRectangle (im, 0, 0, gdImageSX (im), gdImageSY (im), white->c); black = (color_struct *) malloc (sizeof (color_struct)); black->r = black->g = black->b = black->a = 0; black->c = gdImageColorAllocate (im, black->r, black->g, black->b); if (black->c == BADC) { Message ("%s(): gdImageColorAllocateAlpha() returned NULL. Aborting export.\n", __FUNCTION__); return; } f = fopen (filename, "wb"); if (!f) { perror (filename); return; } if (!options[HA_as_shown].int_value) hid_save_and_show_layer_ons (save_ons); png_hid_export_to_file (f, options); if (!options[HA_as_shown].int_value) hid_restore_layer_ons (save_ons); if (photo_mode) { int x, y; color_struct white, black, fr4; rgb (&white, 255, 255, 255); rgb (&black, 0, 0, 0); rgb (&fr4, 70, 70, 70); im = master_im; if (photo_copper[photo_groups[0]]) ts_bs (photo_copper[photo_groups[0]]); if (photo_silk) ts_bs (photo_silk); if (photo_mask) ts_bs_sm (photo_mask); if (photo_outline && have_outline) { int black=gdImageColorResolve(photo_outline, 0x00, 0x00, 0x00); // go all the way around the image, trying to fill the outline for (x=0; x= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group; if (name == 0) name = PCB->Data->Layer[idx].Name; doing_outline = 0; if (idx >= 0 && idx < max_copper_layer && !print_layer[idx]) return 0; if (SL_TYPE (idx) == SL_ASSY || SL_TYPE (idx) == SL_FAB) return 0; if (strcmp (name, "invisible") == 0) return 0; is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL); is_mask = (SL_TYPE (idx) == SL_MASK); is_copper = (SL_TYPE (idx) == 0); if (is_drill && fill_holes) return 0; if (SL_TYPE (idx) == SL_PASTE) return 0; if (photo_mode) { switch (idx) { case SL (SILK, TOP): if (photo_flip) return 0; photo_im = &photo_silk; break; case SL (SILK, BOTTOM): if (!photo_flip) return 0; photo_im = &photo_silk; break; case SL (MASK, TOP): if (photo_flip) return 0; photo_im = &photo_mask; break; case SL (MASK, BOTTOM): if (!photo_flip) return 0; photo_im = &photo_mask; break; case SL (PDRILL, 0): case SL (UDRILL, 0): photo_im = &photo_drill; break; default: if (idx < 0) return 0; if (strcmp (name, "outline") == 0) { doing_outline = 1; have_outline = 0; photo_im = &photo_outline; } else photo_im = photo_copper + group; break; } if (! *photo_im) { static color_struct *black = NULL, *white = NULL; *photo_im = gdImageCreate (gdImageSX (im), gdImageSY (im)); if (photo_im == NULL) { Message ("%s(): gdImageCreate(%d, %d) returned NULL. Aborting export.\n", __FUNCTION__, gdImageSX (im), gdImageSY (im)); return 0; } white = (color_struct *) malloc (sizeof (color_struct)); white->r = white->g = white->b = 255; white->a = 0; white->c = gdImageColorAllocate (*photo_im, white->r, white->g, white->b); if (white->c == BADC) { Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__); return 0; } black = (color_struct *) malloc (sizeof (color_struct)); black->r = black->g = black->b = black->a = 0; black->c = gdImageColorAllocate (*photo_im, black->r, black->g, black->b); if (black->c == BADC) { Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__); return 0; } if (idx == SL (PDRILL, 0) || idx == SL (UDRILL, 0)) gdImageFilledRectangle (*photo_im, 0, 0, gdImageSX (im), gdImageSY (im), black->c); } im = *photo_im; return 1; } if (as_shown) { switch (idx) { case SL (SILK, TOP): case SL (SILK, BOTTOM): if (SL_MYSIDE (idx)) return PCB->ElementOn; return 0; case SL (MASK, TOP): case SL (MASK, BOTTOM): return TEST_FLAG (SHOWMASKFLAG, PCB) && SL_MYSIDE (idx); } } else { if (is_mask) return 0; switch (idx) { case SL (SILK, TOP): return 1; case SL (SILK, BOTTOM): return 0; } } return 1; } static hidGC png_make_gc (void) { hidGC rv = (hidGC) malloc (sizeof (hid_gc_struct)); rv->me_pointer = &png_hid; rv->cap = Trace_Cap; rv->width = 1; rv->color = (color_struct *) malloc (sizeof (color_struct)); rv->color->r = rv->color->g = rv->color->b = rv->color->a = 0; rv->color->c = 0; rv->is_erase = 0; return rv; } static void png_destroy_gc (hidGC gc) { free (gc); } static void png_use_mask (enum mask_mode mode) { if (photo_mode) return; if (mode == HID_MASK_CLEAR) { return; } if (mode != HID_MASK_OFF) { if (mask_im == NULL) { mask_im = gdImageCreate (gdImageSX (im), gdImageSY (im)); if (!mask_im) { Message ("%s(): gdImageCreate(%d, %d) returned NULL. Corrupt export!\n", __FUNCTION__, gdImageSY (im), gdImageSY (im)); return; } gdImagePaletteCopy (mask_im, im); } im = mask_im; gdImageFilledRectangle (mask_im, 0, 0, gdImageSX (mask_im), gdImageSY (mask_im), white->c); } else { int x, y, c; im = master_im; for (x=0; xcolor = white; gc->is_erase = 1; return; } gc->is_erase = 0; if (in_mono || (strcmp (name, "#000000") == 0)) { gc->color = black; return; } if (hid_cache_color (0, name, &cval, &color_cache)) { gc->color = (color_struct *)cval.ptr; } else if (name[0] == '#') { gc->color = (color_struct *) malloc (sizeof (color_struct)); sscanf (name + 1, "%2x%2x%2x", &(gc->color->r), &(gc->color->g), &(gc->color->b)); gc->color->c = gdImageColorAllocate (master_im, gc->color->r, gc->color->g, gc->color->b); if (gc->color->c == BADC) { Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__); return; } cval.ptr = gc->color; hid_cache_color (1, name, &cval, &color_cache); } else { printf ("WE SHOULD NOT BE HERE!!!\n"); gc->color = black; } } static void png_set_line_cap (hidGC gc, EndCapStyle style) { gc->cap = style; } static void png_set_line_width (hidGC gc, Coord width) { gc->width = width; } static void png_set_draw_xor (hidGC gc, int xor_) { ; } static void use_gc (hidGC gc) { int need_brush = 0; if (gc->me_pointer != &png_hid) { fprintf (stderr, "Fatal: GC from another HID passed to png HID\n"); abort (); } if (linewidth != gc->width) { /* Make sure the scaling doesn't erase lines completely */ if (SCALE (gc->width) == 0 && gc->width > 0) gdImageSetThickness (im, 1); else gdImageSetThickness (im, SCALE (gc->width + 2*bloat)); linewidth = gc->width; need_brush = 1; } if (lastbrush != gc->brush || need_brush) { hidval bval; char name[256]; char type; int r; switch (gc->cap) { case Round_Cap: case Trace_Cap: type = 'C'; break; default: case Square_Cap: type = 'S'; break; } if (gc->width) r = SCALE (gc->width + 2*bloat); else r = 1; /* do not allow a brush size that is zero width. In this case limit to a single pixel. */ if (r == 0) { r = 1; } sprintf (name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r); if (hid_cache_color (0, name, &bval, &brush_cache)) { gc->brush = (gdImagePtr)bval.ptr; } else { int bg, fg; gc->brush = gdImageCreate (r, r); if (gc->brush == NULL) { Message ("%s(): gdImageCreate(%d, %d) returned NULL. Aborting export.\n", __FUNCTION__, r, r); return; } bg = gdImageColorAllocate (gc->brush, 255, 255, 255); if (bg == BADC) { Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__); return; } fg = gdImageColorAllocateAlpha (gc->brush, gc->color->r, gc->color->g, gc->color->b, 0); if (fg == BADC) { Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__); return; } gdImageColorTransparent (gc->brush, bg); /* * if we shrunk to a radius/box width of zero, then just use * a single pixel to draw with. */ if (r <= 1) gdImageFilledRectangle (gc->brush, 0, 0, 0, 0, fg); else { if (type == 'C') { gdImageFilledEllipse (gc->brush, r/2, r/2, r, r, fg); /* Make sure the ellipse is the right exact size. */ gdImageSetPixel (gc->brush, 0, r/2, fg); gdImageSetPixel (gc->brush, r-1, r/2, fg); gdImageSetPixel (gc->brush, r/2, 0, fg); gdImageSetPixel (gc->brush, r/2, r-1, fg); } else gdImageFilledRectangle (gc->brush, 0, 0, r-1, r-1, fg); } bval.ptr = gc->brush; hid_cache_color (1, name, &bval, &brush_cache); } gdImageSetBrush (im, gc->brush); lastbrush = gc->brush; } } static void png_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { use_gc (gc); gdImageRectangle (im, SCALE_X (x1), SCALE_Y (y1), SCALE_X (x2), SCALE_Y (y2), gc->color->c); } static void png_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { use_gc (gc); gdImageSetThickness (im, 0); linewidth = 0; y1 -= bloat; y2 += bloat; SWAP_IF_SOLDER (y1, y2); gdImageFilledRectangle (im, SCALE_X (x1-bloat), SCALE_Y (y1), SCALE_X (x2+bloat)-1, SCALE_Y (y2)-1, gc->color->c); have_outline |= doing_outline; } static void png_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { if (x1 == x2 && y1 == y2) { Coord w = gc->width / 2; if (gc->cap != Square_Cap) png_fill_circle (gc, x1, y1, w); else png_fill_rect (gc, x1 - w, y1 - w, x1 + w, y1 + w); return; } use_gc (gc); if (NOT_EDGE (x1, y1) || NOT_EDGE (x2, y2)) have_outline |= doing_outline; if (doing_outline) { /* Special case - lines drawn along the bottom or right edges are brought in by a pixel to make sure we have contiguous outlines. */ if (x1 == PCB->MaxWidth && x2 == PCB->MaxWidth) { x1 -= scale/2; x2 -= scale/2; } if (y1 == PCB->MaxHeight && y2 == PCB->MaxHeight) { y1 -= scale/2; y2 -= scale/2; } } gdImageSetThickness (im, 0); linewidth = 0; if(gc->cap != Square_Cap || x1 == x2 || y1 == y2 ) { gdImageLine (im, SCALE_X (x1), SCALE_Y (y1), SCALE_X (x2), SCALE_Y (y2), gdBrushed); } else { /* * if we are drawing a line with a square end cap and it is * not purely horizontal or vertical, then we need to draw * it as a filled polygon. */ int fg = gdImageColorResolve (im, gc->color->r, gc->color->g, gc->color->b); Coord w = gc->width; Coord dwx, dwy; gdPoint p[4]; double l = Distance(x1, y1, x2, y2) * 2; w += 2 * bloat; dwx = -w / l * (y2 - y1); dwy = w / l * (x2 - x1); p[0].x = SCALE_X (x1 + dwx - dwy); p[0].y = SCALE_Y(y1 + dwy + dwx); p[1].x = SCALE_X (x1 - dwx - dwy); p[1].y = SCALE_Y(y1 - dwy + dwx); p[2].x = SCALE_X (x2 - dwx + dwy); p[2].y = SCALE_Y(y2 - dwy - dwx); p[3].x = SCALE_X (x2 + dwx + dwy); p[3].y = SCALE_Y(y2 + dwy - dwx); gdImageFilledPolygon (im, p, 4, fg); } } static void png_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle) { Angle sa, ea; /* * zero angle arcs need special handling as gd will output either * nothing at all or a full circle when passed delta angle of 0 or 360. */ if (delta_angle == 0) { Coord x = (width * cos (start_angle * M_PI / 180)); Coord y = (width * sin (start_angle * M_PI / 180)); x = cx - x; y = cy + y; png_fill_circle (gc, x, y, gc->width / 2); return; } /* * in gdImageArc, 0 degrees is to the right and +90 degrees is down * in pcb, 0 degrees is to the left and +90 degrees is down */ start_angle = 180 - start_angle; delta_angle = -delta_angle; if (show_bottom_side) { start_angle = - start_angle; delta_angle = -delta_angle; } if (delta_angle > 0) { sa = start_angle; ea = start_angle + delta_angle; } else { sa = start_angle + delta_angle; ea = start_angle; } /* * make sure we start between 0 and 360 otherwise gd does * strange things */ sa = NormalizeAngle (sa); ea = NormalizeAngle (ea); have_outline |= doing_outline; #if 0 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); printf ("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n", im, SCALE_X (cx), SCALE_Y (cy), SCALE (width), SCALE (height), sa, ea, gc->color->c); #endif use_gc (gc); gdImageSetThickness (im, 0); linewidth = 0; gdImageArc (im, SCALE_X (cx), SCALE_Y (cy), SCALE (2 * width), SCALE (2 * height), sa, ea, gdBrushed); } static void png_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) { Coord my_bloat; use_gc (gc); if (fill_holes && gc->is_erase && is_copper) return; if (gc->is_erase) my_bloat = -2 * bloat; else my_bloat = 2 * bloat; have_outline |= doing_outline; gdImageSetThickness (im, 0); linewidth = 0; gdImageFilledEllipse (im, SCALE_X (cx), SCALE_Y (cy), SCALE (2 * radius + my_bloat), SCALE (2 * radius + my_bloat), gc->color->c); } static void png_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) { int i; gdPoint *points; points = (gdPoint *) malloc (n_coords * sizeof (gdPoint)); if (points == NULL) { fprintf (stderr, "ERROR: png_fill_polygon(): malloc failed\n"); exit (1); } use_gc (gc); for (i = 0; i < n_coords; i++) { if (NOT_EDGE (x[i], y[i])) have_outline |= doing_outline; points[i].x = SCALE_X (x[i]); points[i].y = SCALE_Y (y[i]); } gdImageSetThickness (im, 0); linewidth = 0; gdImageFilledPolygon (im, points, n_coords, gc->color->c); free (points); } static void png_calibrate (double xval, double yval) { CRASH; } static void png_set_crosshair (int x, int y, int a) { } #include "dolists.h" void hid_png_init () { memset (&png_hid, 0, sizeof (HID)); memset (&png_graphics, 0, sizeof (HID_DRAW)); common_nogui_init (&png_hid); common_draw_helpers_init (&png_graphics); png_hid.struct_size = sizeof (HID); png_hid.name = "png"; png_hid.description = "GIF/JPEG/PNG export"; png_hid.exporter = 1; png_hid.poly_before = 1; png_hid.get_export_options = png_get_export_options; png_hid.do_export = png_do_export; png_hid.parse_arguments = png_parse_arguments; png_hid.set_layer = png_set_layer; png_hid.calibrate = png_calibrate; png_hid.set_crosshair = png_set_crosshair; png_hid.graphics = &png_graphics; png_graphics.make_gc = png_make_gc; png_graphics.destroy_gc = png_destroy_gc; png_graphics.use_mask = png_use_mask; png_graphics.set_color = png_set_color; png_graphics.set_line_cap = png_set_line_cap; png_graphics.set_line_width = png_set_line_width; png_graphics.set_draw_xor = png_set_draw_xor; png_graphics.draw_line = png_draw_line; png_graphics.draw_arc = png_draw_arc; png_graphics.draw_rect = png_draw_rect; png_graphics.fill_circle = png_fill_circle; png_graphics.fill_polygon = png_fill_polygon; png_graphics.fill_rect = png_fill_rect; #ifdef HAVE_SOME_FORMAT hid_register_hid (&png_hid); #include "png_lists.h" #endif } pcb-4.2.2/src/hid/lpr/0000775000076400007640000000000013611113567011432 500000000000000pcb-4.2.2/src/hid/lpr/hid.conf0000664000076400007640000000002512575072760012771 00000000000000type=printer deps=ps pcb-4.2.2/src/hid/lpr/lpr.c0000664000076400007640000000670413175446024012324 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "global.h" #include "data.h" #include "misc.h" #include "hid.h" #include "../hidint.h" #include "../ps/ps.h" #include "hid/common/hidnogui.h" #include "hid/common/hidinit.h" #ifdef HAVE_LIBDMALLOC #include #endif #define CRASH fprintf(stderr, \ _("HID error: pcb called unimplemented PS function %s.\n"), \ __FUNCTION__); abort() static HID_Attribute base_lpr_options[] = { /* %start-doc options "98 lpr Printing Options" @ftable @code @item --lprcommand Command to use for printing. Defaults to @code{lpr}. This can be used to produce PDF output with a virtual PDF printer. Example: @* @code{--lprcommand "lp -d CUPS-PDF-Printer"}. @end ftable @noindent In addition, all @ref{Postscript Export} options are valid. %end-doc */ {N_("lprcommand"), N_("Command to use for printing"), HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_lprcommand 0 }; #define NUM_OPTIONS (sizeof(lpr_options)/sizeof(lpr_options[0])) static HID_Attribute *lpr_options = 0; static int num_lpr_options = 0; static HID_Attr_Val *lpr_values; static HID_Attribute * lpr_get_export_options (int *n) { /* * We initialize the default value in this manner because the GUI * HID's may want to free() this string value and replace it with a * new one based on how a user fills out a print dialog. */ if (base_lpr_options[HA_lprcommand].default_val.str_value == NULL) { base_lpr_options[HA_lprcommand].default_val.str_value = strdup("lpr"); } if (lpr_options == 0) { HID_Attribute *ps_opts = ps_hid.get_export_options (&num_lpr_options); lpr_options = (HID_Attribute *) calloc (num_lpr_options, sizeof (HID_Attribute)); memcpy (lpr_options, ps_opts, num_lpr_options * sizeof (HID_Attribute)); memcpy (lpr_options, base_lpr_options, sizeof (base_lpr_options)); lpr_values = (HID_Attr_Val *) calloc (num_lpr_options, sizeof (HID_Attr_Val)); } if (n) *n = num_lpr_options; return lpr_options; } static void lpr_do_export (HID_Attr_Val * options) { FILE *f; int i; const char *filename; if (!options) { lpr_get_export_options (0); for (i = 0; i < num_lpr_options; i++) lpr_values[i] = lpr_options[i].default_val; options = lpr_values; } filename = options[HA_lprcommand].str_value; printf (_("LPR: open %s\n"), filename); f = popen (filename, "w"); if (!f) { perror (filename); return; } ps_hid_export_to_file (f, options); pclose (f); } static void lpr_parse_arguments (int *argc, char ***argv) { lpr_get_export_options (0); hid_register_attributes (lpr_options, num_lpr_options); hid_parse_command_line (argc, argv); } static void lpr_calibrate (double xval, double yval) { ps_calibrate_1 (xval, yval, 1); } static HID lpr_hid; void hid_lpr_init () { memset (&lpr_hid, 0, sizeof (HID)); common_nogui_init (&lpr_hid); ps_ps_init (&lpr_hid); lpr_hid.struct_size = sizeof (HID); lpr_hid.name = "lpr"; lpr_hid.description = N_("Postscript print"); lpr_hid.printer = 1; lpr_hid.poly_before = 1; lpr_hid.get_export_options = lpr_get_export_options; lpr_hid.do_export = lpr_do_export; lpr_hid.parse_arguments = lpr_parse_arguments; lpr_hid.calibrate = lpr_calibrate; hid_register_hid (&lpr_hid); } pcb-4.2.2/src/hid/gsvit/0000775000076400007640000000000013611113567011771 500000000000000pcb-4.2.2/src/hid/gsvit/gsvit_lists.h0000664000076400007640000000005213611070713014424 00000000000000REGISTER_ATTRIBUTES(gsvit_attribute_list) pcb-4.2.2/src/hid/gsvit/hid.conf0000664000076400007640000000001413533277055013325 00000000000000type=export pcb-4.2.2/src/hid/gsvit/xmlout.h0000664000076400007640000000312613533277055013422 00000000000000#ifndef _XMLOUT #define _XMLOUT 1 #include struct s_xmlout { FILE* fd; int count; }; struct s_xmlout xmlout; char* indent[] = { "\n", "\n\t", "\n\t\t", "\n\t\t\t", "\n\t\t\t\t", "\n\t\t\t\t\t", "\n\t\t\t\t\t\t", "\n\t\t\t\t\t\t\t" }; #define XPUTS fputs #define XPRINTF fprintf #define XNEWLINE indent[xmlout.count] #define XOUT_DETENT() if(xmlout.count) xmlout.count-- #define XOUT_INDENT() xmlout.count++ #define XOUT_ELEMENT_2ATTR_START(name, id1, val1, id2, val2) XPRINTF(xmlout.fd, "<%s %s=\"%s\" %s=\"%s\">", name, id1, val1, id2, val2); #define XOUT_ELEMENT_ATTR_START(name, id, val) XPRINTF(xmlout.fd, "<%s %s=\"%s\">", name, id, val); #define XOUT_ELEMENT_START(name) XPRINTF(xmlout.fd, "<%s>", name); #define XOUT_ELEMENT_END(name) XPRINTF(xmlout.fd, "", name); #define XOUT_ELEMENT_EMPTY(name) XPRINTF(xmlout.fd, "<%s/>", name) #define XOUT_ELEMENT_ATTR_EMPTY(name, id, val) XPRINTF(xmlout.fd, "<%s %s=\"%s\"/>", name, id, val) #define XOUT_ELEMENT_DATA(data) XPRINTF(xmlout.fd, "%s", data) #define XOUT_NEWLINE() XPUTS( XNEWLINE, xmlout.fd) #define XOUT_ELEMENT(name, data) XOUT_ELEMENT_START(name);\ XOUT_ELEMENT_DATA(data);\ XOUT_ELEMENT_END(name); #define XOUT_ELEMENT_ATTR(name, id, val, data) XOUT_ELEMENT_ATTR_START(name, id, val);\ XOUT_ELEMENT_DATA(data);\ XOUT_ELEMENT_END(name); #define XOUT_HEADER() XPRINTF(xmlout.fd, ""); #define XOUT_INIT(filename) xmlout.count=0;\ xmlout.fd = fopen(filename, "w") #define XOUT_CLOSE() xmlout.count=0;\ fclose(xmlout.fd); \ xmlout.fd = NULL #endif pcb-4.2.2/src/hid/gsvit/gsvit.c0000664000076400007640000013600413533277055013223 00000000000000/*! * \file src/hid/gsvit/gsvit.c * * \brief HID exporter for gsvit. * * This HID exports a PCB layout into: * - One layer mask file (PNG format) per copper layer. * - a gsvit configuration file that contains netlist and pin * information. * * \bug If you have a section of a net that does not contain any pins * then that section will be missing from the gsvit's copper geometry.\n * * \note Single layer layouts are always exported correctly. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 1994, 1995, 1996, 2004 Thomas Nau * * Based on the NELMA (Numerical capacitance calculator) export HID * Copyright (C) 2006 Tomaz Solc (tomaz.solc@tablix.org) * * PNG export code is based on the PNG export HID * Copyright (C) 2006 Dan McMahill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * *
*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "global.h" #include "error.h" /* Message() */ #include "data.h" #include "misc.h" #include "rats.h" #include "find.h" #include "flags.h" #include "hid.h" #include "hid_draw.h" #include "../hidint.h" #include "hid/common/hidnogui.h" #include "hid/common/draw_helpers.h" #include #include "xmlout.h" #include "hid/common/hidinit.h" #include "pcb-printf.h" #ifdef HAVE_LIBDMALLOC #include #endif #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort() #define MAXREFPINS 32 /* max length of following list */ static char *reference_pin_names[] = {"1", "2", "A1", "A2", "B1", "B2", 0}; /* Needed for PNG export */ struct color_struct { /* the descriptor used by the gd library */ int c; /* so I can figure out what rgb value c refers to */ unsigned int r, g, b; }; struct hid_gc_struct { HID *me_pointer; EndCapStyle cap; Coord width; unsigned char r, g, b; int erase; struct color_struct *color; gdImagePtr brush; }; struct gsvit_net_layer { GList *Line; GList *Arc; GList *Polygon; }; struct gsvit_netlist { char* name; GList *Pin; GList *Via; GList *Pad; struct gsvit_net_layer layer[MAX_LAYER]; struct color_struct color; int colorIndex; }; /*! * \brief Structure to represent a single hole. */ struct drill_hole { int cx; int cy; int is_plated; }; /*! * \brief Structure to represent all holes of a given size. */ struct single_size_drills { double diameter_inches; Coord radius; int n_holes; int n_holes_allocated; struct drill_hole* holes; }; static struct single_size_drills* drills = NULL; typedef struct _StringList { char *str; struct _StringList *next; } StringList; typedef struct _BomList { char *descr; char *value; int num; StringList *refdes; struct _BomList *next; } BomList; static int n_drills = 0; /*!< At the start we have no drills at all */ static int n_drills_allocated = 0; static int save_drill = 0; static int is_plated = 0; struct gsvit_netlist* gsvit_netlist = NULL; int hashColor = gdBrushed; static struct color_struct* color_array[0x100]; static HID gsvit_hid; static HID_DRAW gsvit_graphics; static struct color_struct *black = NULL, *white = NULL; static Coord linewidth = -1; static gdImagePtr lastbrush = (gdImagePtr)((void *) -1); /*! * \brief gd image for PNG export. */ static gdImagePtr gsvit_im = NULL; /*! * \brief file for PNG export. */ static FILE *gsvit_f = NULL; static int is_mask; static int is_drill; /*! * \brief Which groups of layers to export into PNG layer masks. * * 1 means export; 0 means do not export. */ static int gsvit_export_group[MAX_GROUP]; /*! * \brief Group that is currently exported. */ static int gsvit_cur_group; /*! * \brief Filename prefix that will be used when saving files. */ static const char *gsvit_basename = NULL; /*! * \brief Horizontal DPI (grid points per inch). */ static int gsvit_dpi = -1; HID_Attribute gsvit_attribute_list[] = { /* other HIDs expect this to be first. */ /* %start-doc options "96 gsvit Options" @ftable @code @item -- basename File name prefix. @end ftable %end-doc */ {"basename", "File name prefix", HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_basename 0 /* %start-doc options "96 gsvit Options" @ftable @code @item --dpi Horizontal scale factor (grid points/inch). @end ftable %end-doc */ {"dpi", "Horizontal scale factor (grid points/inch)", HID_Integer, 0, 1000, {1000, 0, 0}, 0, 0}, /* 1000 --> 1 mil (25.4 um) resolution */ #define HA_dpi 1 }; #define NUM_OPTIONS (sizeof (gsvit_attribute_list) / sizeof (gsvit_attribute_list[0])) REGISTER_ATTRIBUTES(gsvit_attribute_list) static HID_Attr_Val gsvit_values[NUM_OPTIONS]; void gsvit_create_netlist (void); void gsvit_destroy_netlist (void); static void gsvit_xml_out (char* gsvit_basename); static void gsvit_build_net_from_selected (struct gsvit_netlist* currNet); static void gsvit_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); static void gsvit_write_xnets (void); /*! * \brief Convert HSL to RGB. * * From http://www.rapidtables.com/convert/color/hsl-to-rgb.htm * * Converts from (H)ue (S)aturation and (L)ightness to (R)ed, (G)reen * and (B)lue. * * h range 0 - 365 degrees * * s range 0 - 255 * * l range 0 - 255 * * \return rgb array of chars in range of 0-255 0-->R, 1-->G, 2-->B. * * \note Always returns a result, wraps 'h' if > 360 degrees. */ char * hslToRgb (int h, uint8_t s, uint8_t l) { static char rgb[3]; float H = fmod ((float)(h), 360.0); float S = s; float L = l; int sect; float C, X; float m; float Rp, Gp, Bp; L /= 255.0; S /= 255.0; sect = h / 60; C = (1.0 - fabs (2 * L - 1.0)) * S; X = C * (1.0 - fabs (fmod ((H / 60.0), 2.0) - 1.0)); m = L - C / 2.0; switch (sect) { case 0: Rp = C; Gp = X; Bp = 0.0; break; case 1: Rp = X; Gp = C; Bp = 0.0; break; case 2: Rp = 0.0; Gp = C; Bp = X; break; case 3: Rp = 0.0; Gp = X; Bp = C; break; case 4: Rp = X; Gp = 0.0; Bp = C; break; case 5: Rp = C; Gp = 0.0; Bp = X; break; default: Rp = 0.0; Gp = 0.0; Bp = 0.0; break; } rgb[0] = (Rp + m) * 0xFF; rgb[1] = (Gp + m) * 0xFF; rgb[2] = (Bp + m) * 0xFF; return (rgb); } void gsvit_build_net_from_selected (struct gsvit_netlist* currNet) { COPPERLINE_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, line)) { currNet->layer[l].Line = g_list_prepend(currNet->layer[l].Line, line); } } ENDALL_LOOP; COPPERARC_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, arc)) { currNet->layer[l].Arc = g_list_prepend (currNet->layer[l].Arc, arc); } } ENDALL_LOOP; COPPERPOLYGON_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, polygon)) { currNet->layer[l].Polygon = g_list_prepend (currNet->layer[l].Polygon, polygon); } } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, pad)) { currNet->Pad = g_list_prepend (currNet->Pad, pad); } } ENDALL_LOOP; ALLPIN_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, pin)) { currNet->Pin = g_list_prepend (currNet->Pin, pin); } } ENDALL_LOOP; VIA_LOOP (PCB->Data); { if (TEST_FLAG (SELECTEDFLAG, via)) { currNet->Via = g_list_prepend(currNet->Via, via); } } END_LOOP; } void gsvit_create_netlist (void) { int i; int numNets = PCB->NetlistLib.MenuN; gsvit_netlist = (struct gsvit_netlist*) malloc (sizeof (struct gsvit_netlist) * numNets); memset (gsvit_netlist, 0, sizeof (struct gsvit_netlist) * numNets); for (i = 0; i < numNets; i++) { /* For each net in the netlist. */ int j; LibraryEntryType* entry; ConnectionType conn; struct gsvit_netlist* currNet = &gsvit_netlist[i]; currNet->name = PCB->NetlistLib.Menu[i].Name + 2; /*! \todo Add fancy color attachment here. */ InitConnectionLookup (); ClearFlagOnAllObjects (FOUNDFLAG | SELECTEDFLAG, false); for (j = PCB->NetlistLib.Menu[i].EntryN, entry = PCB->NetlistLib.Menu[i].Entry; j; j--, entry++) { /* For each component (pin/pad) in the net. */ if (SeekPad(entry, &conn, false)) { RatFindHook(conn.type, conn.ptr1, conn.ptr2, conn.ptr2, false, SELECTEDFLAG, false); } } /* The conn should now contain a list of all elements that are part * of the net. * Now build a database of all things selected as part of this net. */ gsvit_build_net_from_selected (currNet); ClearFlagOnAllObjects (FOUNDFLAG | SELECTEDFLAG, false); FreeConnectionLookupMemory (); } /* Assign colors to nets. */ for (i = 0; i < numNets; i++) { char *rgb = NULL; char name[0x100]; int j; int phase = (360 * i) / numNets; for (j = 0; gsvit_netlist[i].name[j]; j++) { name[j] = tolower (gsvit_netlist[i].name[j]); } name[j] = 0; /*! \todo Probably a '\0' character is better code. */ if (strstr (name, "gnd") || strstr (name, "ground")) { /* Make gnd nets darker. */ rgb = hslToRgb (phase, (70 * 256) / 100, (20 * 256) / 100); } else if (strstr (name, "unnamed")) {/* Make unnamed nets grayer. */ rgb = hslToRgb (phase, (15 * 256) / 100, (40 * 256) / 100); } else rgb = hslToRgb (phase, (70 * 256) / 100, (50 * 256) / 100); gsvit_netlist[i].color.r = rgb[0]; gsvit_netlist[i].color.g = rgb[1]; gsvit_netlist[i].color.b = rgb[2]; } } void gsvit_destroy_netlist (void) { int i; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { /* For each net in the netlist. */ struct gsvit_netlist* currNet = &gsvit_netlist[i]; int j; for (j = 0; j < MAX_LAYER; j++) { g_list_free (currNet->layer[j].Line); g_list_free (currNet->layer[j].Arc); g_list_free (currNet->layer[j].Polygon); } g_list_free (currNet->Pad); g_list_free (currNet->Pin); g_list_free (currNet->Via); } free (gsvit_netlist); } /*! * \brief Convert from default PCB units to gsvit units. */ static int pcb_to_gsvit (Coord pcb) { return COORD_TO_INCH (pcb) * gsvit_dpi; } static char * gsvit_get_png_name (const char *basename, const char *suffix) { char *buf; int len; len = strlen (basename) + strlen(suffix) + 6; buf = (char *) malloc (sizeof (*buf) * len); sprintf (buf, "%s.%s.png", basename, suffix); return buf; } static void gsvit_write_xspace (void) { double xh; uint32_t h; uint32_t w; char buff[0x100]; int i, idx; const char *ext; char *src; xh = (1000.0* 2.54e-2) / ((double) gsvit_dpi); /* Units are in mm. */ h = (uint32_t) pcb_to_gsvit (PCB->MaxHeight); /* Units are in counts. */ w = (uint32_t) pcb_to_gsvit (PCB->MaxWidth); sprintf (buff, "%f", xh); XOUT_ELEMENT_START ("space"); XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT ("comment", "***** Space *****"); XOUT_NEWLINE (); XOUT_ELEMENT_ATTR ("resolution", "units", "mm", buff); XOUT_NEWLINE (); sprintf (buff, "%d", w); XOUT_ELEMENT ("width", buff); XOUT_NEWLINE (); sprintf (buff, "%d", h); XOUT_ELEMENT ("height", buff); XOUT_NEWLINE (); XOUT_ELEMENT_START ("layers"); XOUT_INDENT (); for (i = 0; i < MAX_GROUP; i++) if (gsvit_export_group[i]) { idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i; ext = layer_type_to_file_name (idx, FNS_fixed); src = gsvit_get_png_name (gsvit_basename, ext); XOUT_NEWLINE (); XOUT_ELEMENT_ATTR ("layer", "name", ext, src); } XOUT_DETENT (); XOUT_NEWLINE (); XOUT_ELEMENT_END ("layers"); XOUT_DETENT (); XOUT_NEWLINE (); XOUT_ELEMENT_END ("space"); XOUT_DETENT (); } static void gsvit_write_xnets (void) { LibraryType netlist; LibraryMenuType *net; LibraryEntryType *pin; int n, m, i, idx; netlist = PCB->NetlistLib; XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT_START ("nets"); XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT ("comment", "***** Nets *****"); XOUT_NEWLINE (); for (n = 0; n < netlist.MenuN; n++) { char buff[0x100]; net = &netlist.Menu[n]; /* Weird, but correct */ XOUT_ELEMENT_ATTR_START ("net", "name", &net->Name[2]); // snprintf(buff, 0x100, "%d,%d,%d", net->color.r, net->color.g, net->color.b); // XOUT_ELEMENT_2ATTR_START("net", "name", &net->Name[2], "color", buff ); for (m = 0; m < net->EntryN; m++) { pin = &net->Entry[m]; /* pin_name_to_xy(pin, &x, &y); */ for (i = 0; i < MAX_GROUP; i++) if (gsvit_export_group[i]) { idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i; layer_type_to_file_name (idx, FNS_fixed); if (m != 0 || i != 0) XOUT_ELEMENT_DATA (", "); snprintf (buff, 0x100, "%s", pin->ListEntry); { char* src = buff; while (*src) { if (*src == '-') *src = '.'; src++; } } XOUT_ELEMENT_DATA (buff); break; } } XOUT_ELEMENT_END ("net"); if (n+1 >= netlist.MenuN) XOUT_DETENT (); XOUT_NEWLINE (); } XOUT_ELEMENT_END ("nets"); XOUT_DETENT (); } static StringList * string_insert (char *str, StringList *list) { StringList *newlist, *cur; if ((newlist = (StringList *) malloc (sizeof (StringList))) == NULL) { fprintf (stderr, "malloc() failed in string_insert()\n"); exit (1); } newlist->next = NULL; newlist->str = strdup (str); if (list == NULL) return (newlist); cur = list; while (cur->next != NULL) cur = cur->next; cur->next = newlist; return (list); } static BomList * bom_insert (char *refdes, char *descr, char *value, BomList * bom) { BomList *newlist, *cur, *prev = NULL; if (bom == NULL) { /* this is the first element so automatically create an entry */ if ((newlist = (BomList *) malloc (sizeof (BomList))) == NULL) { fprintf (stderr, "malloc() failed in bom_insert()\n"); exit (1); } newlist->next = NULL; newlist->descr = strdup (descr); newlist->value = strdup (value); newlist->num = 1; newlist->refdes = string_insert (refdes, NULL); return (newlist); } /* search and see if we already have used one of these components */ cur = bom; while (cur != NULL) { if ((NSTRCMP (descr, cur->descr) == 0) && (NSTRCMP (value, cur->value) == 0)) { cur->num++; cur->refdes = string_insert (refdes, cur->refdes); break; } prev = cur; cur = cur->next; } if (cur == NULL) { if ((newlist = (BomList *) malloc (sizeof (BomList))) == NULL) { fprintf (stderr, "malloc() failed in bom_insert()\n"); exit (1); } prev->next = newlist; newlist->next = NULL; newlist->descr = strdup (descr); newlist->value = strdup (value); newlist->num = 1; newlist->refdes = string_insert (refdes, NULL); } return (bom); } static double xyToAngle (double x, double y, bool morethan2pins) { double d = atan2 (-y, x) * 180.0 / M_PI; /* IPC 7351 defines different rules for 2 pin elements */ if (morethan2pins) { /* Multi pin case: * Output 0 degrees if pin1 in is top left or top, i.e. between angles of * 80 to 170 degrees. * Pin #1 can be at dead top (e.g. certain PLCCs) or anywhere in the top * left. */ if (d < -100) return 90; /* -180 to -100 */ else if (d < -10) return 180; /* -100 to -10 */ else if (d < 80) return 270; /* -10 to 80 */ else if (d < 170) return 0; /* 80 to 170 */ else return 90; /* 170 to 180 */ } else { /* 2 pin element: * Output 0 degrees if pin #1 is in top left or left, i.e. in sector * between angles of 95 and 185 degrees. */ if (d < -175) return 0; /* -180 to -175 */ else if (d < -85) return 90; /* -175 to -85 */ else if (d < 5) return 180; /* -85 to 5 */ else if (d < 95) return 270; /* 5 to 95 */ else return 0; /* 95 to 180 */ } } /*! * \brief Main export callback. */ static void gsvit_parse_arguments (int *argc, char ***argv) { hid_register_attributes (gsvit_attribute_list, sizeof (gsvit_attribute_list) / sizeof (gsvit_attribute_list[0])); hid_parse_command_line(argc, argv); } static HID_Attribute * gsvit_get_export_options (int *n) { static char *last_made_filename = 0; if (PCB) { derive_default_filename (PCB->Filename, &gsvit_attribute_list[HA_basename], ".gsvit", &last_made_filename); } if (n) { *n = NUM_OPTIONS; } return gsvit_attribute_list; } static char* CleanXBOMString (char *in) { char *out; // int i; char* src; char* dest; if ((out = (char *)malloc ((strlen (in) + 1+0x40) * sizeof (char))) == NULL) { fprintf (stderr, "Error: CleanBOMString() malloc() failed\n"); exit (1); } dest = out; src = in; while(*src != '\0') { switch (*src) { case '<': *dest++ = '&'; *dest++ = 'l'; *dest++ = 't'; *dest = ';'; break; case '&': *dest++ = '&'; *dest++ = 'a'; *dest++ = 'm'; *dest++ = 'p'; *dest = ';'; break; default: *dest = *src; } src++; dest++; } return out; } static void gsvit_write_xdrills (void) { int i = 0; int j; char buff[0x100]; XOUT_NEWLINE (); XOUT_ELEMENT_START ("drills"); XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT ("comment", "***** Drills *****"); for (i = 0; i < n_drills; i++) { snprintf (buff, 0x100, "D%d", i); XOUT_NEWLINE (); XOUT_ELEMENT_ATTR_START ("drill", "id", buff); XOUT_INDENT (); snprintf (buff, 0x100, "%g", drills[i].diameter_inches); XOUT_NEWLINE (); XOUT_ELEMENT ("dia_inches", buff); snprintf (buff, 0x100, "%d", pcb_to_gsvit(drills[i].radius)); XOUT_NEWLINE (); XOUT_ELEMENT ("radius", buff); for (j = 0; j < drills[i].n_holes; j++) { snprintf (buff, 0x100, "%d,%d", drills[i].holes[j].cx, drills[i].holes[j].cy); XOUT_NEWLINE (); if (drills[i].holes[j].is_plated) { XOUT_ELEMENT_ATTR_START ("pos", "type", "plated"); } else { XOUT_ELEMENT_ATTR_START ("pos", "type", "unplated"); } XOUT_ELEMENT_DATA (buff); XOUT_ELEMENT_END ("pos"); } XOUT_DETENT (); XOUT_NEWLINE (); XOUT_ELEMENT_END ("drill"); } // if (drills[i].diameter_inches >= diameter_inches) // break; XOUT_DETENT (); XOUT_NEWLINE (); XOUT_ELEMENT_END ("drills"); XOUT_DETENT (); XOUT_NEWLINE (); } static void gsvit_write_xcentroids (void) { char buff[0x100]; Coord x, y; double theta = 0.0; double sumx, sumy; int pinfound[MAXREFPINS]; double pinx[MAXREFPINS]; double piny[MAXREFPINS]; double pinangle[MAXREFPINS]; double padcentrex, padcentrey; double centroidx, centroidy; double pin1x, pin1y; int pin_cnt; int found_any_not_at_centroid; int found_any; BomList *bom = NULL; char *name, *descr, *value,*fixed_rotation; int rpindex; XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT_START ("centroids"); XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT ("comment", "***** Centroids *****"); /* * For each element we calculate the centroid of the footprint. * In addition, we need to extract some notion of rotation. * While here generate the BOM list */ ELEMENT_LOOP (PCB->Data); { /* Initialize our pin count and our totals for finding the centroid. */ pin_cnt = 0; sumx = 0.0; sumy = 0.0; for (rpindex = 0; rpindex < MAXREFPINS; rpindex++) pinfound[rpindex] = 0; /* Insert this component into the bill of materials list. */ bom = bom_insert ((char *)UNKNOWN (NAMEONPCB_NAME (element)), (char *)UNKNOWN (DESCRIPTION_NAME (element)), (char *)UNKNOWN (VALUE_NAME (element)), bom); /* * Iterate over the pins and pads keeping a running count of how * many pins/pads total and the sum of x and y coordinates * * While we're at it, store the location of pin/pad #1 and #2 if * we can find them. */ PIN_LOOP (element); { sumx += (double) pin->X; sumy += (double) pin->Y; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pin->Number, reference_pin_names[rpindex]) == 0){ pinx[rpindex] = (double) pin->X; piny[rpindex] = (double) pin->Y; pinangle[rpindex] = 0.0; /* pins have no notion of angle */ pinfound[rpindex] = 1; } } } END_LOOP; PAD_LOOP (element); { sumx += (pad->Point1.X + pad->Point2.X) / 2.0; sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pad->Number, reference_pin_names[rpindex]) == 0) { padcentrex = (double) (pad->Point1.X + pad->Point2.X) / 2.0; padcentrey = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0; pinx[rpindex] = padcentrex; piny[rpindex] = padcentrey; /* * NOTE: We swap the Y points because in PCB, the Y-axis * is inverted. Increasing Y moves down. We want to deal * in the usual increasing Y moves up coordinates though. */ pinangle[rpindex] = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y, pad->Point2.X - pad->Point1.X); pinfound[rpindex]=1; } } } END_LOOP; if (pin_cnt > 0) { centroidx = sumx / (double) pin_cnt; centroidy = sumy / (double) pin_cnt; if (NSTRCMP (AttributeGetFromList (&element->Attributes,"xy-centre"), "origin") == 0 ) { x = element->MarkX; y = element->MarkY; } else { x = centroidx; y = centroidy; } fixed_rotation = AttributeGetFromList (&element->Attributes, "xy-fixed-rotation"); if (fixed_rotation) { /* The user specified a fixed rotation */ theta = atof (fixed_rotation); found_any_not_at_centroid = 1; found_any = 1; } else { /* Find first reference pin not at the centroid */ found_any_not_at_centroid = 0; found_any = 0; theta = 0.0; for (rpindex = 0; reference_pin_names[rpindex] && !found_any_not_at_centroid; rpindex++) { if (pinfound[rpindex]) { found_any = 1; /* Recenter pin "#1" onto the axis which cross at the part * centroid. */ pin1x = pinx[rpindex] - x; pin1y = piny[rpindex] - y; /* flip x, to reverse rotation for elements on back. */ if (FRONT (element) != 1) pin1x = -pin1x; /* if only 1 pin, use pin 1's angle */ if (pin_cnt == 1) { theta = pinangle[rpindex]; found_any_not_at_centroid = 1; } else if ((pin1x != 0.0) || (pin1y != 0.0)) { theta = xyToAngle (pin1x, pin1y, pin_cnt > 2); found_any_not_at_centroid = 1; } } } if (!found_any) { Message ("PrintBOM(): unable to figure out angle because I could\n" " not find a suitable reference pin of element %s\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } else if (!found_any_not_at_centroid) { Message ("PrintBOM(): unable to figure out angle of element\n" " %s because the reference pin(s) are at the centroid of the part.\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } } name = CleanXBOMString ((char *)UNKNOWN (NAMEONPCB_NAME (element))); descr = CleanXBOMString ((char *)UNKNOWN (DESCRIPTION_NAME (element))); value = CleanXBOMString ((char *)UNKNOWN (VALUE_NAME (element))); y = PCB->MaxHeight - y; XOUT_NEWLINE (); XOUT_ELEMENT_ATTR_START ("xy", "name", name); XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT ("description", descr); XOUT_NEWLINE (); XOUT_ELEMENT ("value", value); XOUT_NEWLINE (); snprintf (buff, 0x100, "%d,%d", pcb_to_gsvit(x), pcb_to_gsvit(y)); XOUT_ELEMENT ("pos", buff); XOUT_NEWLINE (); pcb_snprintf (buff, 0x100, "%g", theta); XOUT_ELEMENT ("rotation", buff); XOUT_NEWLINE (); XOUT_ELEMENT ("side", FRONT (element) == 1 ? "top" : "bottom"); XOUT_DETENT (); XOUT_NEWLINE (); XOUT_ELEMENT_END ("xy"); free (name); free (descr); free (value); } } END_LOOP; XOUT_DETENT (); XOUT_NEWLINE (); XOUT_ELEMENT_END ("centroids"); } /*! * \brief Populates gsvit_export_group array. */ void gsvit_choose_groups () { int n, m; LayerType *layer; /* Set entire array to 0 (don't export any layer groups by default */ memset (gsvit_export_group, 0, sizeof (gsvit_export_group)); for (n = 0; n < max_copper_layer; n++) { layer = &PCB->Data->Layer[n]; if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN) { /* Layer isn't empty. */ /*! \todo Is this check necessary? It seems that special layers * have negative indexes? */ if (SL_TYPE(n) == 0) { /* Layer is a copper layer. */ m = GetLayerGroupNumberByNumber (n); /* The export layer. */ gsvit_export_group[m] = 1; } } } } /*! * \brief Allocate colors. * * White and black, the first color allocated becomes the background * color. */ static void gsvit_alloc_colors () { int i; int numNets = PCB->NetlistLib.MenuN; char *rgb; white = (struct color_struct *) malloc (sizeof (*white)); white->r = white->g = white->b = 255; white->c = gdImageColorAllocate (gsvit_im, white->r, white->g, white->b); black = (struct color_struct *) malloc (sizeof (*black)); black->r = black->g = black->b = 0; black->c = gdImageColorAllocate (gsvit_im, black->r, black->g, black->b); for (i = 0; i < numNets; i++) { gsvit_netlist[i].colorIndex = i; color_array[i] = malloc (sizeof (*white)); color_array[i]->r = gsvit_netlist[i].color.r; color_array[i]->g = gsvit_netlist[i].color.g; color_array[i]->b = gsvit_netlist[i].color.b; color_array[i]->c = gdImageColorAllocate (gsvit_im, color_array[i]->r, color_array[i]->g, color_array[i]->b); } color_array[i] = malloc (sizeof (*white)); rgb = hslToRgb (128, (20 * 256) / 100, (20 * 256) / 100); color_array[i]->r = rgb[0]; color_array[i]->g = rgb[1]; color_array[i]->b = rgb[2]; color_array[i]->c = gdImageColorAllocate (gsvit_im, color_array[i]->r, color_array[i]->g, color_array[i]->b); printf ("%d colors allocated\n", numNets); } static void gsvit_start_png (const char *basename, const char *suffix) { int h, w; char *buf; buf = gsvit_get_png_name (basename, suffix); h = pcb_to_gsvit (PCB->MaxHeight); w = pcb_to_gsvit (PCB->MaxWidth); /* gsvit only works with true color images. */ gsvit_im = gdImageCreate (w, h); gsvit_f = fopen (buf, "wb"); gsvit_alloc_colors (); free (buf); } static void gsvit_finish_png () { int i; #ifdef HAVE_GDIMAGEPNG gdImagePng (gsvit_im, gsvit_f); #else Message ("gsvit: PNG not supported by gd. Can't write layer mask.\n"); #endif gdImageDestroy (gsvit_im); fclose (gsvit_f); for (i = 0; i < 0x100; i++) { free (color_array[i]); } gsvit_im = NULL; gsvit_f = NULL; } void gsvit_start_png_export () { BoxType region; region.X1 = 0; region.Y1 = 0; region.X2 = PCB->MaxWidth; region.Y2 = PCB->MaxHeight; linewidth = -1; lastbrush = (gdImagePtr)((void *) -1); hid_expose_callback (&gsvit_hid, ®ion, 0); } static void gsvit_do_export (HID_Attr_Val *options) { int save_ons[MAX_ALL_LAYER]; int i, idx; char *buf; int len; if (!options) { gsvit_get_export_options(0); for (i = 0; i < NUM_OPTIONS; i++) { gsvit_values[i] = gsvit_attribute_list[i].default_val; } options = gsvit_values; } gsvit_basename = options[HA_basename].str_value; if (!gsvit_basename) { gsvit_basename = "pcb-out"; } gsvit_dpi = options[HA_dpi].int_value; if (gsvit_dpi < 0) { fprintf (stderr, "ERROR: dpi may not be < 0\n"); return; } gsvit_create_netlist (); gsvit_choose_groups (); for (i = 0; i < MAX_GROUP; i++) { if (gsvit_export_group[i]) { gsvit_cur_group = i; /* Magic. */ idx = (i >= 0 && i < max_group) ? PCB->LayerGroups.Entries[i][0] : i; save_drill = (GetLayerGroupNumberByNumber (idx) == GetLayerGroupNumberBySide (BOTTOM_SIDE)) ? 1 : 0; /* save drills for one layer only */ gsvit_start_png (gsvit_basename, layer_type_to_file_name (idx, FNS_fixed)); hid_save_and_show_layer_ons (save_ons); gsvit_start_png_export (); hid_restore_layer_ons (save_ons); gsvit_finish_png (); } } len = strlen (gsvit_basename) + 4; buf = (char *) malloc (sizeof (*buf) * len); gsvit_xml_out ((char*) gsvit_basename); gsvit_destroy_netlist (); } void gsvit_xml_out (char *gsvit_basename) { char *buf; int len; time_t t; len = strlen (gsvit_basename) + 4; buf = (char *) malloc (sizeof (*buf) * len); sprintf (buf, "%s.xem", gsvit_basename); XOUT_INIT (buf); free (buf); XOUT_HEADER (); XOUT_NEWLINE (); XOUT_ELEMENT_START ("gsvit"); XOUT_INDENT (); XOUT_NEWLINE (); XOUT_ELEMENT ("comment", "Made with PCB gsvit export HID"); XOUT_NEWLINE (); { char buff[0x100 + 1]; char* src = buff; t = time (NULL); strncpy (buff, ctime(&t), 0x100); while (*src) { if ((*src =='\r') || (*src =='\n')) { *src = 0; break; } src++; } XOUT_ELEMENT ("genTime", buff); XOUT_NEWLINE (); } gsvit_write_xspace (); gsvit_write_xnets (); gsvit_write_xcentroids(); gsvit_write_xdrills(); XOUT_ELEMENT_END ("gsvit"); XOUT_NEWLINE (); XOUT_CLOSE (); } /* *** PNG export (slightly modified code from PNG export HID) ************* */ static int gsvit_set_layer (const char *name, int group, int empty) { int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group; if (name == 0) { name = PCB->Data->Layer[idx].Name; } if (strcmp(name, "invisible") == 0) { return 0; } is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL); is_mask = (SL_TYPE (idx) == SL_MASK); if (is_mask) { /* Don't print masks. */ return 0; } if (is_drill) { if (SL_TYPE(idx) == SL_PDRILL) is_plated =1; else if (SL_TYPE(idx) == SL_UDRILL) is_plated =0; /* Print 'holes', so that we can fill gaps in the copper layer. */ return 1; } if (group == gsvit_cur_group) { return 1; } return 0; } static hidGC gsvit_make_gc (void) { hidGC rv = (hidGC) malloc (sizeof (struct hid_gc_struct)); rv->me_pointer = &gsvit_hid; rv->cap = Trace_Cap; rv->width = 1; rv->color = (struct color_struct *) malloc (sizeof (*rv->color)); rv->color->r = rv->color->g = rv->color->b = 0; rv->color->c = 0; return rv; } static void gsvit_destroy_gc (hidGC gc) { free (gc); } static void gsvit_use_mask (enum mask_mode mode) { /* Do nothing. */ } static void gsvit_set_color (hidGC gc, const char *name) { if (gsvit_im == NULL) { return; } if (name == NULL) { name = "#ff0000"; } if (!strcmp(name, "drill")) { gc->color = black; gc->erase = 0; return; } if (!strcmp(name, "erase")) { /*! \todo Should be background, not white. */ gc->color = white; gc->erase = 1; return; } gc->color = black; gc->erase = 0; return; } static void gsvit_set_line_cap (hidGC gc, EndCapStyle style) { gc->cap = style; } static void gsvit_set_line_width (hidGC gc, Coord width) { gc->width = width; } static void gsvit_set_draw_xor (hidGC gc, int xor_) { /* Do nothing. */ } static void gsvit_set_draw_faded (hidGC gc, int faded) { /* Do nothing. */ } static void use_gc (hidGC gc) { int need_brush = 0; if (gc->me_pointer != &gsvit_hid) { fprintf (stderr, "Fatal: GC from another HID passed to gsvit HID\n"); abort (); } if (hashColor != gdBrushed) { need_brush = 1; } if (linewidth != gc->width) { /* Make sure the scaling doesn't erase lines completely */ /* if (SCALE (gc->width) == 0 && gc->width > 0) gdImageSetThickness (im, 1); else */ gdImageSetThickness (gsvit_im, pcb_to_gsvit (gc->width)); linewidth = gc->width; need_brush = 1; } if (lastbrush != gc->brush || need_brush) { static void *bcache = 0; hidval bval; char name[256]; char type; int r; switch (gc->cap) { case Round_Cap: case Trace_Cap: type = 'C'; r = pcb_to_gsvit (gc->width / 2); break; default: case Square_Cap: r = pcb_to_gsvit(gc->width); type = 'S'; break; } sprintf (name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r); /* if (hid_cache_color(0, name, &bval, &bcache)) { gc->brush = (gdImagePtr) bval.ptr; } else { */ { int bg, fg; if (type == 'C') gc->brush = gdImageCreate (2 * r + 1, 2 * r + 1); else gc->brush = gdImageCreate (r + 1, r + 1); bg = gdImageColorAllocate (gc->brush, 255, 255, 255); if (hashColor != gdBrushed) { /* printf ("hash:%d\n",hashColor); */ fg = gdImageColorAllocate (gc->brush, color_array[hashColor]->r,color_array[hashColor]->g,color_array[hashColor]->b); } else { fg = gdImageColorAllocate (gc->brush, gc->color->r, gc->color->g, gc->color->b); } gdImageColorTransparent (gc->brush, bg); /* If we shrunk to a radius/box width of zero, then just use a * single pixel to draw with. */ if (r == 0) { gdImageFilledRectangle (gc->brush, 0, 0, 0, 0, fg); } else { if (type == 'C') gdImageFilledEllipse (gc->brush, r, r, 2 * r, 2 * r, fg); else gdImageFilledRectangle (gc->brush, 0, 0, r, r, fg); } bval.ptr = gc->brush; hid_cache_color (1, name, &bval, &bcache); } gdImageSetBrush (gsvit_im, gc->brush); lastbrush = gc->brush; } } static void gsvit_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { use_gc (gc); gdImageRectangle (gsvit_im, pcb_to_gsvit (x1), pcb_to_gsvit (y1), pcb_to_gsvit (x2), pcb_to_gsvit (y2), gc->color->c); } static void gsvit_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { use_gc (gc); gdImageSetThickness (gsvit_im, 0); linewidth = 0; gdImageFilledRectangle (gsvit_im, pcb_to_gsvit (x1), pcb_to_gsvit (y1), pcb_to_gsvit (x2), pcb_to_gsvit (y2), gc->color->c); } struct gsvit_netlist * gsvit_lookup_net_from_arc (ArcType *targetArc) { int i; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { /* For each net in the netlist. */ struct gsvit_netlist *currNet = &gsvit_netlist[i]; int j; for (j = 0; j < PCB->LayerGroups.Number[gsvit_cur_group]; j++) { /* For each layer of the current group. */ int layer = PCB->LayerGroups.Entries[gsvit_cur_group][j]; ARC_LOOP (&(currNet->layer[layer])); { if (targetArc == arc) return (currNet); } END_LOOP; } } return (NULL); } struct gsvit_netlist * gsvit_lookup_net_from_line (LineType *targetLine) { int i; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { /* For each net in the netlist. */ struct gsvit_netlist* currNet = &gsvit_netlist[i]; int j; for (j = 0; j < PCB->LayerGroups.Number[gsvit_cur_group]; j++) { /* For each layer of the current group. */ int layer = PCB->LayerGroups.Entries[gsvit_cur_group][j]; LINE_LOOP (&(currNet->layer[layer])); { if (targetLine == line) return (currNet); } END_LOOP; } } return (NULL); } struct gsvit_netlist * gsvit_lookup_net_from_polygon (PolygonType *targetPolygon) { int i; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { /* For each net in the netlist. */ struct gsvit_netlist* currNet = &gsvit_netlist[i]; int j; for (j = 0; j < PCB->LayerGroups.Number[gsvit_cur_group]; j++) { /* For each layer of the current group. */ int layer = PCB->LayerGroups.Entries[gsvit_cur_group][j]; POLYGON_LOOP (&(currNet->layer[layer])); { if (targetPolygon == polygon) return (currNet); } END_LOOP; } } return (NULL); } struct gsvit_netlist * gsvit_lookup_net_from_pad (PadType *targetPad) { int i; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { /* For each net in the netlist. */ struct gsvit_netlist* currNet = &gsvit_netlist[i]; PAD_LOOP (currNet); { if (targetPad == pad) return (currNet); } END_LOOP; } return (NULL); } struct gsvit_netlist * gsvit_lookup_net_from_pv (PinType *targetPv) { int i; for (i = 0; i < PCB->NetlistLib.MenuN; i++) { /* For each net in the netlist. */ struct gsvit_netlist* currNet = &gsvit_netlist[i]; PIN_LOOP (currNet); { if (targetPv == pin) return (currNet); } END_LOOP; VIA_LOOP (currNet); { if (targetPv == via) return (currNet); } END_LOOP; } return (NULL); } static void add_hole (struct single_size_drills* drill, int cx, int cy) { if (drill->n_holes == drill->n_holes_allocated) { drill->n_holes_allocated += 100; drill->holes = (struct drill_hole *) realloc (drill->holes,drill->n_holes_allocated *sizeof (struct drill_hole)); } drill->holes[drill->n_holes].cx = cx; drill->holes[drill->n_holes].cy = cy; drill->holes[drill->n_holes].is_plated = is_plated; drill->n_holes++; printf ("holes %d\n", drill->n_holes); } /*! * \brief Given a hole size, return the structure that currently holds * the data for that hole size. * * If there isn't one, make it. */ static int _drill_size_comparator (const void* _size0, const void* _size1) { double size0 = ((const struct single_size_drills*)_size0)->diameter_inches; double size1 = ((const struct single_size_drills*)_size1)->diameter_inches; if (size0 == size1) return 0; if (size0 < size1) return -1; return 1; } static struct single_size_drills * get_drill (double diameter_inches, Coord radius) { /* See if we already have this size. If so, return that structure. */ struct single_size_drills* drill = bsearch (&diameter_inches, drills, n_drills, sizeof (drills[0]), _drill_size_comparator); if (drill != NULL) return( drill); /* Haven't seen this hole size before, so make a new structure for it. */ if (n_drills == n_drills_allocated) { n_drills_allocated += 100; drills = (struct single_size_drills *) realloc (drills, n_drills_allocated * sizeof (struct single_size_drills)); } /* I now add the structure to the list, making sure to keep the list * sorted. Ideally the bsearch() call above would have given me the location * to insert this element while keeping things sorted, but it doesn't. For * simplicity I manually lsearch() to find this location myself */ { int i = 0; for (i = 0; i= diameter_inches) break; if (n_drills != i) memmove (&drills[i+1], &drills[i], (n_drills-i) * sizeof (struct single_size_drills)); drills[i].diameter_inches = diameter_inches; drills[i].radius = radius; drills[i].n_holes = 0; drills[i].n_holes_allocated = 0; drills[i].holes = NULL; n_drills++; return &drills[i]; } } static void gsvit_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { if (x1 == x2 && y1 == y2) { Coord w = gc->width / 2; gsvit_fill_rect (gc, x1 - w, y1 - w, x1 + w, y1 + w); return; } linewidth = -1; use_gc (gc); linewidth = -1; gdImageSetThickness (gsvit_im, 0); linewidth = 0; gdImageLine (gsvit_im, pcb_to_gsvit (x1), pcb_to_gsvit (y1), pcb_to_gsvit (x2), pcb_to_gsvit (y2), gdBrushed); } static void gsvit_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle) { Angle sa, ea; /* In gdImageArc, 0 degrees is to the right and +90 degrees is down. * in pcb, 0 degrees is to the left and +90 degrees is down. */ start_angle = 180 - start_angle; delta_angle = -delta_angle; if (delta_angle > 0) { sa = start_angle; ea = start_angle + delta_angle; } else { sa = start_angle + delta_angle; ea = start_angle; } /* Make sure we start between 0 and 360 otherwise gd does strange * things. */ sa = NormalizeAngle (sa); ea = NormalizeAngle (ea); #if 0 printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n", im, SCALE_X (cx), SCALE_Y (cy), SCALE (width), SCALE (height), sa, ea, gc->color->c); #endif use_gc (gc); gdImageSetThickness (gsvit_im, 0); linewidth = 0; gdImageArc (gsvit_im, pcb_to_gsvit (cx), pcb_to_gsvit (cy), pcb_to_gsvit (2 * width), pcb_to_gsvit (2 * height), sa, ea, gdBrushed); } static void gsvit_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) { use_gc (gc); gdImageSetThickness (gsvit_im, 0); linewidth = 0; gdImageFilledEllipse (gsvit_im, pcb_to_gsvit (cx), pcb_to_gsvit (cy), pcb_to_gsvit (2 * radius), pcb_to_gsvit (2 * radius), color_array[hashColor]->c); if (save_drill && is_drill) { double diameter_inches = COORD_TO_INCH(radius*2); struct single_size_drills* drill = get_drill (diameter_inches, radius); add_hole(drill, pcb_to_gsvit(cx), pcb_to_gsvit(cy)); /* convert to inch, flip: will drill from bottom side */ // COORD_TO_INCH(PCB->MaxWidth - cx), /* PCB reverses y axis */ // COORD_TO_INCH(PCB->MaxHeight - cy)); } } static void gsvit_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) { int i; gdPoint *points; points = (gdPoint *) malloc (n_coords * sizeof (gdPoint)); if (points == NULL) { fprintf (stderr, "ERROR: gsvit_fill_polygon(): malloc failed\n"); exit (1); } use_gc (gc); for (i = 0; i < n_coords; i++) { points[i].x = pcb_to_gsvit (x[i]); points[i].y = pcb_to_gsvit (y[i]); } gdImageSetThickness (gsvit_im, 0); linewidth = 0; gdImageFilledPolygon (gsvit_im, points, n_coords, color_array[hashColor]->c); free (points); } static void gsvit_calibrate (double xval, double yval) { CRASH; } static void gsvit_set_crosshair (int x, int y, int a) { /* Do nothing. */ } static void gsvit_draw_pcb_arc (hidGC gc, ArcType *arc) { struct gsvit_netlist *net; net = gsvit_lookup_net_from_arc (arc); if (net) { hashColor = net->colorIndex; } else { hashColor = PCB->NetlistLib.MenuN; } common_draw_pcb_arc (gc, arc); hashColor = PCB->NetlistLib.MenuN; } static void gsvit_draw_pcb_line (hidGC gc, LineType *line) { struct gsvit_netlist *net; net = gsvit_lookup_net_from_line (line); if (net) { hashColor = net->colorIndex; } else { hashColor = PCB->NetlistLib.MenuN; } common_draw_pcb_line (gc, line); hashColor = PCB->NetlistLib.MenuN; } void gsvit_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box) { /* Hijack the fill_pcb_polygon function to get *poly, then proceed * with the default handler. */ struct gsvit_netlist *net; net = gsvit_lookup_net_from_polygon (poly); if (net) { hashColor = net->colorIndex; } else { hashColor = PCB->NetlistLib.MenuN; } common_fill_pcb_polygon (gc, poly, clip_box); hashColor = PCB->NetlistLib.MenuN; } void gsvit_fill_pcb_pad (hidGC gc, PadType *pad, bool clear, bool mask) { struct gsvit_netlist *net = NULL; net = gsvit_lookup_net_from_pad(pad); if (net) { hashColor = net->colorIndex; } else { hashColor = PCB->NetlistLib.MenuN; } common_fill_pcb_pad (gc, pad, clear, mask); hashColor = PCB->NetlistLib.MenuN; } void gsvit_fill_pcb_pv (hidGC fg_gc, hidGC bg_gc, PinType *pv, bool drawHole, bool mask) { struct gsvit_netlist *net = NULL; net = gsvit_lookup_net_from_pv (pv); if (net) { hashColor = net->colorIndex; } else { hashColor = PCB->NetlistLib.MenuN; } common_fill_pcb_pv (fg_gc, bg_gc, pv, drawHole, mask); hashColor = PCB->NetlistLib.MenuN; } #include "dolists.h" void hid_gsvit_init () { memset (&gsvit_hid, 0, sizeof (HID)); memset (&gsvit_graphics, 0, sizeof (HID_DRAW)); common_nogui_init (&gsvit_hid); common_draw_helpers_init (&gsvit_graphics); //hid_gtk_init(); gsvit_hid.struct_size = sizeof (HID); gsvit_hid.name = "gsvit"; gsvit_hid.description = "Numerical analysis package export"; gsvit_hid.exporter = 1; gsvit_hid.poly_before = 1; gsvit_hid.get_export_options = gsvit_get_export_options; gsvit_hid.do_export = gsvit_do_export; gsvit_hid.parse_arguments = gsvit_parse_arguments; gsvit_hid.set_layer = gsvit_set_layer; gsvit_hid.calibrate = gsvit_calibrate; gsvit_hid.set_crosshair = gsvit_set_crosshair; gsvit_hid.graphics = &gsvit_graphics; gsvit_graphics.make_gc = gsvit_make_gc; gsvit_graphics.destroy_gc = gsvit_destroy_gc; gsvit_graphics.use_mask = gsvit_use_mask; gsvit_graphics.set_color = gsvit_set_color; gsvit_graphics.set_line_cap = gsvit_set_line_cap; gsvit_graphics.set_line_width = gsvit_set_line_width; gsvit_graphics.set_draw_xor = gsvit_set_draw_xor; gsvit_graphics.set_draw_faded = gsvit_set_draw_faded; gsvit_graphics.draw_line = gsvit_draw_line; gsvit_graphics.draw_arc = gsvit_draw_arc; gsvit_graphics.draw_rect = gsvit_draw_rect; gsvit_graphics.fill_circle = gsvit_fill_circle; gsvit_graphics.fill_polygon = gsvit_fill_polygon; gsvit_graphics.fill_rect = gsvit_fill_rect; /* Hijack these functions because what is passed to fill_polygon is a * series of polygons (for holes,...). */ gsvit_graphics.draw_pcb_line = gsvit_draw_pcb_line; gsvit_graphics.draw_pcb_arc = gsvit_draw_pcb_arc; gsvit_graphics.draw_pcb_polygon = gsvit_fill_pcb_polygon; gsvit_graphics.fill_pcb_polygon = gsvit_fill_pcb_polygon; gsvit_graphics.fill_pcb_pad = gsvit_fill_pcb_pad; gsvit_graphics.fill_pcb_pv = gsvit_fill_pcb_pv; hid_register_hid (&gsvit_hid); #include "gsvit_lists.h" } pcb-4.2.2/src/hid/bom/0000775000076400007640000000000013611113567011412 500000000000000pcb-4.2.2/src/hid/bom/hid.conf0000664000076400007640000000001411660653115012740 00000000000000type=export pcb-4.2.2/src/hid/bom/bom.c0000664000076400007640000004722213533277055012270 00000000000000/*! * \file src/hid/bom/bom.c * * \brief Prints a centroid file in a format which includes data needed * by a pick and place machine. * * Further formatting for a particular factory setup can easily be * generated with awk or perl. * In addition, a bill of materials file is generated which can be used * for checking stock and purchasing needed materials. * returns != zero on error. * *
* *

Copyright.

\n * * PCB, interactive printed circuit board design * * Copyright (C) 2006 DJ Delorie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * *
*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "global.h" #include "data.h" #include "error.h" #include "misc.h" #include "pcb-printf.h" #include "hid.h" #include "hid/common/hidnogui.h" #include "../hidint.h" #ifdef HAVE_LIBDMALLOC #include #endif static HID_Attribute bom_options[] = { /* %start-doc options "80 BOM Creation" @ftable @code @item --bomfile Name of the BOM output file. Parameter @code{} can include a path. @end ftable %end-doc */ {"bomfile", "Name of the BOM output file", HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_bomfile 0 /* %start-doc options "80 BOM Creation" @ftable @code @item --xyfile Name of the XY output file. Parameter @code{} can include a path. @end ftable %end-doc */ {"xyfile", "Name of the XY output file", HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_xyfile 1 /* %start-doc options "80 BOM Creation" @ftable @code @item --attrs Name of the attributes input file. Parameter @code{} can include a path. The input file can be any path, the format matches what gschem uses. One attribute per line, and whitespace is ignored. Example: @example device manufacturer manufacturer_part_number vendor vendor_part_number @end example @end ftable %end-doc */ {"attrs", "Name of the attributes input file", HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_attrs 2 /* %start-doc options "80 BOM Creation" @ftable @code @item --xy-unit Unit of XY dimensions. Defaults to mil. Parameter @code{} can be @samp{km}, @samp{m}, @samp{cm}, @samp{mm}, @samp{um}, @samp{nm}, @samp{px}, @samp{in}, @samp{mil}, @samp{dmil}, @samp{cmil}, or @samp{inch}. @end ftable %end-doc */ {"xy-unit", "XY units", HID_Unit, 0, 0, {-1, 0, 0}, NULL, 0}, #define HA_unit 3 {"xy-in-mm", ATTR_UNDOCUMENTED, HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_xymm 4 }; #define NUM_OPTIONS (sizeof(bom_options)/sizeof(bom_options[0])) static HID_Attr_Val bom_values[NUM_OPTIONS]; static const char *bom_filename; static const char *xy_filename; static const Unit *xy_unit; static char **attr_list = NULL; static int attr_count = 0; static int attr_max = 0; typedef struct _StringList { char *str; struct _StringList *next; } StringList; typedef struct _BomList { char *descr; char *value; int num; StringList *refdes; char **attrs; struct _BomList *next; } BomList; static HID_Attribute * bom_get_export_options (int *n) { static char *last_bom_filename = 0; static char *last_xy_filename = 0; static int last_unit_value = -1; if (bom_options[HA_unit].default_val.int_value == last_unit_value) { if (Settings.grid_unit) bom_options[HA_unit].default_val.int_value = Settings.grid_unit->index; else bom_options[HA_unit].default_val.int_value = get_unit_struct ("mil")->index; last_unit_value = bom_options[HA_unit].default_val.int_value; } if (PCB) { derive_default_filename(PCB->Filename, &bom_options[HA_bomfile], ".bom", &last_bom_filename); derive_default_filename(PCB->Filename, &bom_options[HA_xyfile ], ".xy" , &last_xy_filename ); } if (!bom_options[HA_attrs].default_val.str_value) bom_options[HA_attrs].default_val.str_value = strdup("attribs"); if (n) *n = NUM_OPTIONS; return bom_options; } static char * CleanBOMString (char *in) { char *out; int i; if ((out = (char *)malloc ((strlen (in) + 1) * sizeof (char))) == NULL) { fprintf (stderr, "Error: CleanBOMString() malloc() failed\n"); exit (1); } /* * copy over in to out with some character conversions. * Go all the way to then end to get the terminating \0 */ for (i = 0; i <= strlen (in); i++) { switch (in[i]) { case '"': out[i] = '\''; break; default: out[i] = in[i]; } } return out; } static double xyToAngle (double x, double y, bool morethan2pins) { double d = atan2 (-y, x) * 180.0 / M_PI; /* IPC 7351 defines different rules for 2 pin elements */ if (morethan2pins) { /* Multi pin case: * Output 0 degrees if pin1 in is top left or top, i.e. between angles of * 80 to 170 degrees. * Pin #1 can be at dead top (e.g. certain PLCCs) or anywhere in the top * left. */ if (d < -100) return 90; /* -180 to -100 */ else if (d < -10) return 180; /* -100 to -10 */ else if (d < 80) return 270; /* -10 to 80 */ else if (d < 170) return 0; /* 80 to 170 */ else return 90; /* 170 to 180 */ } else { /* 2 pin element: * Output 0 degrees if pin #1 is in top left or left, i.e. in sector * between angles of 95 and 185 degrees. */ if (d < -175) return 0; /* -180 to -175 */ else if (d < -85) return 90; /* -175 to -85 */ else if (d < 5) return 180; /* -85 to 5 */ else if (d < 95) return 270; /* 5 to 95 */ else return 0; /* 95 to 180 */ } } static StringList * string_insert (char *str, StringList * list) { StringList *newlist, *cur; if ((newlist = (StringList *) malloc (sizeof (StringList))) == NULL) { fprintf (stderr, "malloc() failed in string_insert()\n"); exit (1); } newlist->next = NULL; newlist->str = strdup (str); if (list == NULL) return (newlist); cur = list; while (cur->next != NULL) cur = cur->next; cur->next = newlist; return (list); } static BomList * bom_insert (char *refdes, char *descr, char *value, ElementType *e, BomList * bom) { BomList *newlist = NULL, *cur = NULL, *prev = NULL; int i; char *val; if (bom != NULL) { /* search and see if we already have used one of these components */ cur = bom; while (cur != NULL) { int attr_mismatch = 0; for (i=0; iattrs[i]) != 0) attr_mismatch = 1; } if ((NSTRCMP (descr, cur->descr) == 0) && (NSTRCMP (value, cur->value) == 0) && ! attr_mismatch) { cur->num++; cur->refdes = string_insert (refdes, cur->refdes); return (bom); } prev = cur; cur = cur->next; } } if ((newlist = (BomList *) malloc (sizeof (BomList))) == NULL) { fprintf (stderr, "malloc() failed in bom_insert()\n"); exit (1); } if (prev) prev->next = newlist; newlist->next = NULL; newlist->descr = strdup (descr); newlist->value = strdup (value); newlist->num = 1; newlist->refdes = string_insert (refdes, NULL); if ((newlist->attrs = (char **) malloc (attr_count * sizeof (char *))) == NULL) { fprintf (stderr, "malloc() failed in bom_insert()\n"); exit (1); } for (i=0; iattrs[i] = val ? val : ""; } if (bom == NULL) bom = newlist; return (bom); } /*! * \brief If \c fp is not NULL then print out the bill of materials * contained in \c bom. * Either way, free all memory which has been allocated for bom. */ static void print_and_free (FILE *fp, BomList *bom) { BomList *lastb; StringList *lasts; char *descr, *value; while (bom != NULL) { if (fp) { descr = CleanBOMString (bom->descr); value = CleanBOMString (bom->value); fprintf (fp, "%d,\"%s\",\"%s\",", bom->num, descr, value); free (descr); free (value); } while (bom->refdes != NULL) { if (fp) { fprintf (fp, "%s ", bom->refdes->str); } free (bom->refdes->str); lasts = bom->refdes; bom->refdes = bom->refdes->next; free (lasts); } if (fp) { int i; for (i=0; iattrs[i]); fprintf (fp, "\n"); } free (bom->attrs); lastb = bom; bom = bom->next; free (lastb); } } static void fetch_attr_list () { int i; FILE *f; char buf[1024]; char *fname; if (attr_list != NULL) { for (i=0; i= buf && isspace (*c)) *c-- = 0; c = buf; while (*c && isspace (*c)) c++; if (*c) { if (attr_count == attr_max) { attr_max += 10; attr_list = (char **) realloc (attr_list, attr_max * sizeof (char *)); } attr_list[attr_count++] = strdup (c); } } fclose (f); } /*! * Maximum length of following list. */ #define MAXREFPINS 32 /*! * \brief Includes numbered and BGA pins. * * In order of preference. * Possibly BGA pins can be missing, so we add a few to try. */ static char *reference_pin_names[] = {"1", "2", "A1", "A2", "B1", "B2", 0}; static int PrintBOM (void) { char utcTime[64]; Coord x, y; double theta = 0.0; double sumx, sumy; int pinfound[MAXREFPINS]; double pinx[MAXREFPINS]; double piny[MAXREFPINS]; double pinangle[MAXREFPINS]; double padcentrex, padcentrey; double centroidx, centroidy; double pin1x, pin1y; int pin_cnt; int found_any_not_at_centroid; int found_any; time_t currenttime; FILE *fp; BomList *bom = NULL; char *name, *descr, *value,*fixed_rotation; int rpindex; int i; char fmt[256]; sprintf(fmt, "%%s,\"%%s\",\"%%s\",%%.2`m%c,%%.2`m%c,%%g,%%s\n", xy_unit->printf_code, xy_unit->printf_code); fp = fopen (xy_filename, "wb"); if (!fp) { gui->log ("Cannot open file %s for writing\n", xy_filename); return 1; } fetch_attr_list (); /* Create a portable timestamp. */ currenttime = time (NULL); { /* avoid gcc complaints */ const char *fmt = "%c UTC"; strftime (utcTime, sizeof (utcTime), fmt, gmtime (¤ttime)); } fprintf (fp, "# PcbXY Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB X-Y\n", UNKNOWN (PCB->Name)); fprintf (fp, "# RefDes, Description, Value, X, Y, rotation, top/bottom\n"); /* don't use localized xy_unit->in_suffix here since */ /* the line itself is not localized and not for GUI */ fprintf (fp, "# X,Y in %s. rotation in degrees.\n", xy_unit->suffix); fprintf (fp, "# --------------------------------------------\n"); /* * For each element we calculate the centroid of the footprint. * In addition, we need to extract some notion of rotation. * While here generate the BOM list */ ELEMENT_LOOP (PCB->Data); { /* Initialize our pin count and our totals for finding the centroid. */ pin_cnt = 0; sumx = 0.0; sumy = 0.0; for (rpindex = 0; rpindex < MAXREFPINS; rpindex++) pinfound[rpindex] = 0; /* Insert this component into the bill of materials list. */ bom = bom_insert ((char *)UNKNOWN (NAMEONPCB_NAME (element)), (char *)UNKNOWN (DESCRIPTION_NAME (element)), (char *)UNKNOWN (VALUE_NAME (element)), element, bom); /* * Iterate over the pins and pads keeping a running count of how * many pins/pads total and the sum of x and y coordinates * * While we're at it, store the location of pin/pad #1 and #2 if * we can find them. */ PIN_LOOP (element); { sumx += (double) pin->X; sumy += (double) pin->Y; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pin->Number, reference_pin_names[rpindex]) == 0) { pinx[rpindex] = (double) pin->X; piny[rpindex] = (double) pin->Y; pinangle[rpindex] = 0.0; /* pins have no notion of angle */ pinfound[rpindex] = 1; } } } END_LOOP; PAD_LOOP (element); { sumx += (pad->Point1.X + pad->Point2.X) / 2.0; sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pad->Number, reference_pin_names[rpindex]) == 0) { padcentrex = (double) (pad->Point1.X + pad->Point2.X) / 2.0; padcentrey = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0; pinx[rpindex] = padcentrex; piny[rpindex] = padcentrey; /* * NOTE: We swap the Y points because in PCB, the Y-axis * is inverted. Increasing Y moves down. We want to deal * in the usual increasing Y moves up coordinates though. */ pinangle[rpindex] = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y, pad->Point2.X - pad->Point1.X); pinfound[rpindex]=1; } } } END_LOOP; if (pin_cnt > 0) { centroidx = sumx / (double) pin_cnt; centroidy = sumy / (double) pin_cnt; if (NSTRCMP( AttributeGetFromList (&element->Attributes,"xy-centre"), "origin") == 0 ) { x = element->MarkX; y = element->MarkY; } else { x = centroidx; y = centroidy; } fixed_rotation = AttributeGetFromList (&element->Attributes, "xy-fixed-rotation"); if (fixed_rotation) { /* The user specified a fixed rotation */ theta = atof (fixed_rotation); found_any_not_at_centroid = 1; found_any = 1; } else { /* Find first reference pin not at the centroid */ found_any_not_at_centroid = 0; found_any = 0; theta = 0.0; for (rpindex = 0; reference_pin_names[rpindex] && !found_any_not_at_centroid; rpindex++) { if (pinfound[rpindex]) { found_any = 1; /* Recenter pin "#1" onto the axis which cross at the part centroid */ pin1x = pinx[rpindex] - x; pin1y = piny[rpindex] - y; /* flip x, to reverse rotation for elements on back */ if (FRONT (element) != 1) pin1x = -pin1x; /* if only 1 pin, use pin 1's angle */ if (pin_cnt == 1) { theta = pinangle[rpindex]; found_any_not_at_centroid = 1; } else if ((pin1x != 0.0) || (pin1y != 0.0)) { theta = xyToAngle (pin1x, pin1y, pin_cnt > 2); found_any_not_at_centroid = 1; } } } if (!found_any) { Message ("PrintBOM(): unable to figure out angle because I could\n" " not find a suitable reference pin of element %s\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } else if (!found_any_not_at_centroid) { Message ("PrintBOM(): unable to figure out angle of element\n" " %s because the reference pin(s) are at the centroid of the part.\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } } name = CleanBOMString ((char *)UNKNOWN (NAMEONPCB_NAME (element))); descr = CleanBOMString ((char *)UNKNOWN (DESCRIPTION_NAME (element))); value = CleanBOMString ((char *)UNKNOWN (VALUE_NAME (element))); y = PCB->MaxHeight - y; //pcb_fprintf (fp, "%m+%s,\"%s\",\"%s\",%.2`mS,%.2`mS,%g,%s\n", pcb_fprintf (fp, fmt, name, descr, value, x, y, theta, FRONT (element) == 1 ? "top" : "bottom"); free (name); free (descr); free (value); } } END_LOOP; fclose (fp); /* Now print out a Bill of Materials file */ fp = fopen (bom_filename, "wb"); if (!fp) { gui->log ("Cannot open file %s for writing\n", bom_filename); print_and_free (NULL, bom); return 1; } fprintf (fp, "# PcbBOM Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB BOM\n", UNKNOWN (PCB->Name)); fprintf (fp, "# Quantity, Description, Value, RefDes"); for (i=0; i #include #include #include #include #include #include #include #include #ifdef HAVE_PWD_H #include #endif #include #include "config.h" #include "global.h" #include "data.h" #include "misc.h" #include "error.h" #include "draw.h" #include "pcb-printf.h" #include "hid.h" #include "hid_draw.h" #include "../hidint.h" #include "hid/common/hidnogui.h" #include "hid/common/draw_helpers.h" #include "hid/common/hidinit.h" #ifdef HAVE_LIBDMALLOC #include #endif #define CRASH fprintf(stderr, "HID error: pcb called unimplemented Gerber function %s.\n", __FUNCTION__); abort() /*----------------------------------------------------------------------------*/ /* Function prototypes */ /*----------------------------------------------------------------------------*/ static HID_Attribute * gerber_get_export_options (int *n); static void gerber_do_export (HID_Attr_Val * options); static void gerber_parse_arguments (int *argc, char ***argv); static int gerber_set_layer (const char *name, int group, int empty); static hidGC gerber_make_gc (void); static void gerber_destroy_gc (hidGC gc); static void gerber_use_mask (enum mask_mode mode); static void gerber_set_color (hidGC gc, const char *name); static void gerber_set_line_cap (hidGC gc, EndCapStyle style); static void gerber_set_line_width (hidGC gc, Coord width); static void gerber_set_draw_xor (hidGC gc, int _xor); static void gerber_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); static void gerber_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle); static void gerber_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); static void gerber_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius); static void gerber_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2); static void gerber_calibrate (double xval, double yval); static void gerber_set_crosshair (int x, int y, int action); static void gerber_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y); /*----------------------------------------------------------------------------*/ /* Utility routines */ /*----------------------------------------------------------------------------*/ /* These are for films */ #define gerberX(pcb, x) ((Coord) (x)) #define gerberY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y))) #define gerberXOffset(pcb, x) ((Coord) (x)) #define gerberYOffset(pcb, y) ((Coord) (-(y))) /* These are for drills */ #define gerberDrX(pcb, x) ((Coord) (x)) #define gerberDrY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y))) /*----------------------------------------------------------------------------*/ /* Private data structures */ /*----------------------------------------------------------------------------*/ static int verbose; static int all_layers; static int metric; static char *x_convspec, *y_convspec; static int is_mask, was_drill; static int is_drill; static enum mask_mode current_mask; static int flash_drills; static int copy_outline_mode; static int name_style; static LayerType *outline_layer; #define print_xcoord(file, pcb, val)\ pcb_fprintf(file, x_convspec, gerberX(pcb, val)) #define print_ycoord(file, pcb, val)\ pcb_fprintf(file, y_convspec, gerberY(pcb, val)) enum ApertureShape { ROUND, /* Shaped like a circle */ OCTAGON, /* octagonal shape */ SQUARE, /* Shaped like a square */ ROUNDCLEAR, /* clearance in negatives */ SQUARECLEAR, THERMAL /* negative thermal relief */ }; typedef enum ApertureShape ApertureShape; /* This is added to the global aperture array indexes to get gerber dcode and macro numbers. */ #define DCODE_BASE 11 typedef struct aperture { int dCode; /* The RS-274X D code */ Coord width; /* Size in pcb units */ ApertureShape shape; /* ROUND/SQUARE etc */ struct aperture *next; } Aperture; typedef struct { Aperture *data; int count; } ApertureList; static ApertureList *layer_aptr_list; static ApertureList *curr_aptr_list; static int layer_list_max; static int layer_list_idx; typedef struct { Coord diam; Coord x; Coord y; } PendingDrills; PendingDrills *pending_drills = NULL; int n_pending_drills = 0, max_pending_drills = 0; /*----------------------------------------------------------------------------*/ /* Defined Constants */ /*----------------------------------------------------------------------------*/ #define AUTO_OUTLINE_WIDTH MIL_TO_COORD(8) /* Auto-geneated outline width of 8 mils */ /*----------------------------------------------------------------------------*/ /* Aperture Routines */ /*----------------------------------------------------------------------------*/ /* Initialize aperture list */ static void initApertureList (ApertureList *list) { list->data = NULL; list->count = 0; } static void deinitApertureList (ApertureList *list) { Aperture *search = list->data; Aperture *next; while (search) { next = search->next; free(search); search = next; } initApertureList (list); } static int aperture_count; static void resetApertures() { int i; for (i = 0; i < layer_list_max; ++i) deinitApertureList (&layer_aptr_list[i]); free (layer_aptr_list); layer_aptr_list = NULL; curr_aptr_list = NULL; layer_list_max = 0; layer_list_idx = 0; aperture_count = 0; } /* Create and add a new aperture to the list */ static Aperture * addAperture (ApertureList *list, Coord width, ApertureShape shape) { Aperture *app = (Aperture *) malloc (sizeof *app); if (app == NULL) return NULL; app->width = width; app->shape = shape; app->dCode = DCODE_BASE + aperture_count++; app->next = list->data; list->data = app; ++list->count; return app; } /* Fetch an aperture from the list with the specified * width/shape, creating a new one if none exists */ static Aperture * findAperture (ApertureList *list, Coord width, ApertureShape shape) { Aperture *search; /* we never draw zero-width lines */ if (width == 0) return NULL; /* Search for an appropriate aperture. */ for (search = list->data; search; search = search->next) if (search->width == width && search->shape == shape) return search; /* Failing that, create a new one */ return addAperture (list, width, shape); } /* Output aperture data to the file */ static void fprintAperture (FILE *f, Aperture *aptr) { switch (aptr->shape) { case ROUND: pcb_fprintf (f, metric ? "%%ADD%dC,%.3`mm*%%\r\n" : "%%ADD%dC,%.4`mi*%%\r\n", aptr->dCode, aptr->width); break; case SQUARE: pcb_fprintf (f, metric ? "%%ADD%dR,%.3`mmX%.3`mm*%%\r\n" : "%%ADD%dR,%.4`miX%.4`mi*%%\r\n", aptr->dCode, aptr->width, aptr->width); break; case OCTAGON: pcb_fprintf (f, metric ? "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n" "%%ADD%dOCT%d*%%\r\n" : "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n" "%%ADD%dOCT%d*%%\r\n", aptr->dCode, (Coord) ((double) aptr->width / COS_22_5_DEGREE), aptr->dCode, aptr->dCode); break; #if 0 case THERMAL: fprintf (f, "%%AMTHERM%d*7,0,0,%.4f,%.4f,%.4f,45*%%\r\n" "%%ADD%dTHERM%d*%%\r\n", dCode, gap / 100000.0, width / 100000.0, finger / 100000.0, dCode, dCode); break; case ROUNDCLEAR: fprintf (f, "%%ADD%dC,%.4fX%.4f*%%\r\n", dCode, gap / 100000.0, width / 100000.0); break; case SQUARECLEAR: fprintf (f, "%%ADD%dR,%.4fX%.4fX%.4fX%.4f*%%\r\n", dCode, gap / 100000.0, gap / 100000.0, width / 100000.0, width / 100000.0); break; #else default: break; #endif } } /* Set the aperture list for the current layer, * expanding the list buffer if needed */ static ApertureList * setLayerApertureList (int layer_idx) { if (layer_idx >= layer_list_max) { int i = layer_list_max; layer_list_max = 2 * (layer_idx + 1); layer_aptr_list = (ApertureList *) realloc (layer_aptr_list, layer_list_max * sizeof (*layer_aptr_list)); for (; i < layer_list_max; ++i) initApertureList (&layer_aptr_list[i]); } curr_aptr_list = &layer_aptr_list[layer_idx]; return curr_aptr_list; } /* --------------------------------------------------------------------------- */ static HID gerber_hid; static HID_DRAW gerber_graphics; typedef struct hid_gc_struct { EndCapStyle cap; int width; int color; int erase; int drill; } hid_gc_struct; static FILE *f = NULL; static char *filename = NULL; static char *filesuff = NULL; static char *layername = NULL; static int lncount = 0; static int finding_apertures = 0; static int pagecount = 0; static int linewidth = -1; static int lastgroup = -1; static int lastcap = -1; static int print_group[MAX_GROUP]; static int print_layer[MAX_ALL_LAYER]; static int lastX, lastY; /* the last X and Y coordinate */ static const char *copy_outline_names[] = { #define COPY_OUTLINE_NONE 0 "none", #define COPY_OUTLINE_MASK 1 "mask", #define COPY_OUTLINE_SILK 2 "silk", #define COPY_OUTLINE_ALL 3 "all", NULL }; static const char *name_style_names[] = { #define NAME_STYLE_FIXED 0 "fixed", #define NAME_STYLE_SINGLE 1 "single", #define NAME_STYLE_FIRST 2 "first", #define NAME_STYLE_EAGLE 3 "eagle", #define NAME_STYLE_HACKVANA 4 "hackvana", #define NAME_STYLE_OSHPARK 5 "oshpark", NULL }; static HID_Attribute gerber_options[] = { /* %start-doc options "90 Gerber Export" @ftable @code @item --gerberfile Gerber output file prefix. Parameter @code{} can include a path. @end ftable %end-doc */ {"gerberfile", "Gerber output file base", HID_String, 0, 0, {0, 0, 0}, 0, 0}, #define HA_gerberfile 0 /* %start-doc options "90 Gerber Export" @ftable @code @item --all-layers Output contains all layers, even empty ones. @end ftable %end-doc */ {"all-layers", "Output all layers, even empty ones", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_all_layers 1 /* %start-doc options "90 Gerber Export" @ftable @code @item --verbose Print file names and aperture counts on stdout. @end ftable %end-doc */ {"verbose", "Print file names and aperture counts on stdout", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_verbose 2 /* %start-doc options "90 Gerber Export" @ftable @code @item --metric Generate metric Gerber and drill files @end ftable %end-doc */ {"metric", "Generate metric Gerber and drill files", HID_Boolean, 0, 0, {0, 0, 0}, 0, 0}, #define HA_metric 3 /* %start-doc options "90 Gerber Export" @ftable @code @item --copy-outline Copy the outline onto other layers. Parameter @code{} can be @samp{none}, @samp{mask}, @samp{silk} or @samp{all}. @end ftable %end-doc */ {"copy-outline", "Copy outline onto other layers", HID_Enum, 0, 0, {0, 0, 0}, copy_outline_names, 0}, #define HA_copy_outline 4 /* %start-doc options "90 Gerber Export" @ftable @code @item --name-style Naming style for individual gerber files. Parameter @code{} can be @samp{fixed}, @samp{single}, @samp{first}, @samp{eagle}, @samp{hackvana} or @samp{oshpark}. @end ftable %end-doc */ {"name-style", "Naming style for individual gerber files", HID_Enum, 0, 0, {0, 0, 0}, name_style_names, 0}, #define HA_name_style 5 }; #define NUM_OPTIONS (sizeof(gerber_options)/sizeof(gerber_options[0])) static HID_Attr_Val gerber_values[NUM_OPTIONS]; static HID_Attribute * gerber_get_export_options (int *n) { static char *last_made_filename = NULL; if (PCB) derive_default_filename(PCB->Filename, &gerber_options[HA_gerberfile], "", &last_made_filename); if (n) *n = NUM_OPTIONS; return gerber_options; } static int layer_stack_sort (const void *va, const void *vb) { int a_layer = *(int *) va; int b_layer = *(int *) vb; int a_group = GetLayerGroupNumberByNumber (a_layer); int b_group = GetLayerGroupNumberByNumber (b_layer); if (b_group != a_group) return b_group - a_group; return b_layer - a_layer; } static void maybe_close_f (FILE *f) { if (f) { if (was_drill) fprintf (f, "M30\r\n"); else fprintf (f, "M02*\r\n"); fclose (f); } } static BoxType region; /* Very similar to layer_type_to_file_name() but appends only a three-character suffix compatible with Eagle's defaults. */ static void assign_eagle_file_suffix (char *dest, int idx) { int group; int nlayers; char *suff = "out"; switch (idx) { case SL (SILK, TOP): suff = "plc"; break; case SL (SILK, BOTTOM): suff = "pls"; break; case SL (MASK, TOP): suff = "stc"; break; case SL (MASK, BOTTOM): suff = "sts"; break; case SL (PDRILL, 0): suff = "drd"; break; case SL (UDRILL, 0): suff = "dru"; break; case SL (PASTE, TOP): suff = "crc"; break; case SL (PASTE, BOTTOM): suff = "crs"; break; case SL (INVISIBLE, 0): suff = "inv"; break; case SL (FAB, 0): suff = "fab"; break; case SL (ASSY, TOP): suff = "ast"; break; case SL (ASSY, BOTTOM): suff = "asb"; break; default: group = GetLayerGroupNumberByNumber(idx); nlayers = PCB->LayerGroups.Number[group]; if (group == GetLayerGroupNumberBySide(TOP_SIDE)) /* Component */ { suff = "cmp"; } else if (group == GetLayerGroupNumberBySide(BOTTOM_SIDE)) /* Solder */ { suff = "sol"; } else if (nlayers == 1 && (strcmp (PCB->Data->Layer[idx].Name, "route") == 0 || strcmp (PCB->Data->Layer[idx].Name, "outline") == 0)) { suff = "oln"; } else { static char buf[20]; sprintf (buf, "ly%d", group); suff = buf; } break; } strcpy (dest, suff); } /* Very similar to layer_type_to_file_name() but appends only a three-character suffix compatible with Hackvana's naming requirements */ static void assign_hackvana_file_suffix (char *dest, int idx) { int group; int nlayers; char *suff = "defau.out"; switch (idx) { case SL (SILK, TOP): suff = "gto"; break; case SL (SILK, BOTTOM): suff = "gbo"; break; case SL (MASK, TOP): suff = "gts"; break; case SL (MASK, BOTTOM): suff = "gbs"; break; case SL (PDRILL, 0): suff = "drl"; break; case SL (UDRILL, 0): suff = "_NPTH.drl"; break; case SL (PASTE, TOP): suff = "gtp"; break; case SL (PASTE, BOTTOM): suff = "gbp"; break; case SL (INVISIBLE, 0): suff = "inv"; break; case SL (FAB, 0): suff = "fab"; break; case SL (ASSY, TOP): suff = "ast"; break; case SL (ASSY, BOTTOM): suff = "asb"; break; default: group = GetLayerGroupNumberByNumber(idx); nlayers = PCB->LayerGroups.Number[group]; if (group == GetLayerGroupNumberBySide(TOP_SIDE)) { suff = "gtl"; } else if (group == GetLayerGroupNumberBySide(BOTTOM_SIDE)) { suff = "gbl"; } else if (nlayers == 1 && (strcmp (PCB->Data->Layer[idx].Name, "route") == 0 || strcmp (PCB->Data->Layer[idx].Name, "outline") == 0)) { suff = "gm1"; } else { static char buf[20]; sprintf (buf, "g%d", group); suff = buf; } break; } strcpy (dest, suff); } /*! * \brief Very similar to layer_type_to_file_name() but appends only a * three-character suffix compatible with OSH Park's naming requirements. * * \note The unplated drill file with the ".TXT" extension will be * merged when the zip file is processed by OSH Park (after uploading). * * \warning Blind and buried vias are not supported by OSH Park. * * \warning Currently 4 layer boards is the maximum OSH Park supports. */ static void assign_oshpark_file_suffix (char *dest, int idx) { int group; int nlayers; char *suff = "default.out"; switch (idx) { case SL (SILK, TOP): suff = "GTO"; break; case SL (SILK, BOTTOM): suff = "GBO"; break; case SL (MASK, TOP): suff = "GTS"; break; case SL (MASK, BOTTOM): suff = "GBS"; break; case SL (PDRILL, 0): suff = "XLN"; break; case SL (UDRILL, 0): suff = "TXT"; break; case SL (PASTE, TOP): suff = "gtp"; break; case SL (PASTE, BOTTOM): suff = "gbp"; break; case SL (INVISIBLE, 0): suff = "inv"; break; case SL (FAB, 0): suff = "fab"; break; case SL (ASSY, TOP): suff = "ast"; break; case SL (ASSY, BOTTOM): suff = "asb"; break; default: group = GetLayerGroupNumberByNumber(idx); nlayers = PCB->LayerGroups.Number[group]; if (group == GetLayerGroupNumberBySide(TOP_SIDE)) { suff = "GTL"; } else if (group == GetLayerGroupNumberBySide(BOTTOM_SIDE)) { suff = "GBL"; } else if (nlayers == 1 && (strcmp (PCB->Data->Layer[idx].Name, "route") == 0 || strcmp (PCB->Data->Layer[idx].Name, "outline") == 0)) { suff = "GKO"; } else { static char buf[20]; sprintf (buf, "G%dL", group); suff = buf; } break; } strcpy (dest, suff); } static void assign_file_suffix (char *dest, int idx, const char *layer_name) { int fns_style; const char *sext = ".gbr"; switch (name_style) { default: case NAME_STYLE_FIXED: fns_style = FNS_fixed; break; case NAME_STYLE_SINGLE: fns_style = FNS_single; break; case NAME_STYLE_FIRST: fns_style = FNS_first; break; case NAME_STYLE_EAGLE: assign_eagle_file_suffix (dest, idx); return; case NAME_STYLE_HACKVANA: assign_hackvana_file_suffix (dest, idx); return; case NAME_STYLE_OSHPARK: assign_oshpark_file_suffix (dest, idx); return; } switch (idx) { case SL (PDRILL, 0): sext = ".cnc"; break; case SL (UDRILL, 0): sext = ".cnc"; break; } strcpy (dest, layer_type_to_file_name_ex (idx, fns_style, layer_name)); strcat (dest, sext); } static void gerber_do_export (HID_Attr_Val * options) { const char *fnbase; int i; static int saved_layer_stack[MAX_LAYER]; int save_ons[MAX_ALL_LAYER]; FlagType save_thindraw; save_thindraw = PCB->Flags; CLEAR_FLAG(THINDRAWFLAG, PCB); CLEAR_FLAG(THINDRAWPOLYFLAG, PCB); CLEAR_FLAG(CHECKPLANESFLAG, PCB); if (!options) { gerber_get_export_options (NULL); for (i = 0; i < NUM_OPTIONS; i++) gerber_values[i] = gerber_options[i].default_val; options = gerber_values; } fnbase = options[HA_gerberfile].str_value; if (!fnbase) fnbase = "pcb-out"; verbose = options[HA_verbose].int_value; metric = options[HA_metric].int_value; if (metric) { x_convspec = "X%.0mu"; y_convspec = "Y%.0mu"; } else { x_convspec = "X%.0mc"; y_convspec = "Y%.0mc"; } all_layers = options[HA_all_layers].int_value; copy_outline_mode = options[HA_copy_outline].int_value; name_style = options[HA_name_style].int_value; outline_layer = NULL; for (i = 0; i < max_copper_layer; i++) { LayerType *layer = PCB->Data->Layer + i; if (strcmp (layer->Name, "outline") == 0 || strcmp (layer->Name, "route") == 0) { outline_layer = layer; } } i = strlen (fnbase); filename = (char *)realloc (filename, i + 40); strcpy (filename, fnbase); strcat (filename, "."); filesuff = filename + strlen (filename); if (all_layers) { memset (print_group, 1, sizeof (print_group)); memset (print_layer, 1, sizeof (print_layer)); } else { memset (print_group, 0, sizeof (print_group)); memset (print_layer, 0, sizeof (print_layer)); } hid_save_and_show_layer_ons (save_ons); for (i = 0; i < max_copper_layer; i++) { LayerType *layer = PCB->Data->Layer + i; if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN) print_group[GetLayerGroupNumberByNumber (i)] = 1; } print_group[GetLayerGroupNumberBySide (BOTTOM_SIDE)] = 1; print_group[GetLayerGroupNumberBySide (TOP_SIDE)] = 1; for (i = 0; i < max_copper_layer; i++) if (print_group[GetLayerGroupNumberByNumber (i)]) print_layer[i] = 1; memcpy (saved_layer_stack, LayerStack, sizeof (LayerStack)); qsort (LayerStack, max_copper_layer, sizeof (LayerStack[0]), layer_stack_sort); linewidth = -1; lastcap = -1; lastgroup = -1; region.X1 = 0; region.Y1 = 0; region.X2 = PCB->MaxWidth; region.Y2 = PCB->MaxHeight; pagecount = 1; resetApertures (); lastgroup = -1; layer_list_idx = 0; finding_apertures = 1; hid_expose_callback (&gerber_hid, ®ion, 0); layer_list_idx = 0; finding_apertures = 0; hid_expose_callback (&gerber_hid, ®ion, 0); memcpy (LayerStack, saved_layer_stack, sizeof (LayerStack)); maybe_close_f (f); f = NULL; hid_restore_layer_ons (save_ons); PCB->Flags = save_thindraw; } static void gerber_parse_arguments (int *argc, char ***argv) { hid_register_attributes (gerber_options, NUM_OPTIONS); hid_parse_command_line (argc, argv); } static int drill_sort (const void *va, const void *vb) { PendingDrills *a = (PendingDrills *) va; PendingDrills *b = (PendingDrills *) vb; if (a->diam != b->diam) return a->diam - b->diam; if (a->x != b->x) return a->x - b->x; return a->y - b->y; } static int gerber_set_layer (const char *name, int group, int empty) { int want_outline; char *cp; int idx = (group >= 0 && group < max_group) ? PCB->LayerGroups.Entries[group][0] : group; if (name == NULL) name = PCB->Data->Layer[idx].Name; if (idx >= 0 && idx < max_copper_layer && !print_layer[idx]) return 0; if (strcmp (name, "invisible") == 0) return 0; if (SL_TYPE (idx) == SL_ASSY) return 0; flash_drills = 0; if (strcmp (name, "outline") == 0 || strcmp (name, "route") == 0) flash_drills = 1; if (is_drill && n_pending_drills) { int i; /* dump pending drills in sequence */ qsort (pending_drills, n_pending_drills, sizeof (pending_drills[0]), drill_sort); for (i = 0; i < n_pending_drills; i++) { if (i == 0 || pending_drills[i].diam != pending_drills[i - 1].diam) { Aperture *ap = findAperture (curr_aptr_list, pending_drills[i].diam, ROUND); fprintf (f, "T%02d\r\n", ap->dCode); } pcb_fprintf (f, metric ? "X%06.0muY%06.0mu\r\n" : "X%06.0mtY%06.0mt\r\n", gerberDrX (PCB, pending_drills[i].x), gerberDrY (PCB, pending_drills[i].y)); } free (pending_drills); n_pending_drills = max_pending_drills = 0; pending_drills = NULL; } is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL); is_mask = (SL_TYPE (idx) == SL_MASK); current_mask = HID_MASK_OFF; #if 0 printf ("Layer %s group %d drill %d mask %d\n", name, group, is_drill, is_mask); #endif if (group < 0 || group != lastgroup) { time_t currenttime; char utcTime[64]; #ifdef HAVE_GETPWUID struct passwd *pwentry; #endif ApertureList *aptr_list; Aperture *search; lastgroup = group; lastX = -1; lastY = -1; linewidth = -1; lastcap = -1; aptr_list = setLayerApertureList (layer_list_idx++); if (finding_apertures) goto emit_outline; if (aptr_list->count == 0 && !all_layers) return 0; maybe_close_f (f); f = NULL; pagecount++; assign_file_suffix (filesuff, idx, name); f = fopen (filename, "wb"); /* Binary needed to force CR-LF */ if (f == NULL) { Message ( "Error: Could not open %s for writing.\n", filename); return 1; } was_drill = is_drill; if (verbose) { int c = aptr_list->count; printf ("Gerber: %d aperture%s in %s\n", c, c == 1 ? "" : "s", filename); } if (is_drill) { /* We omit the ,TZ here because we are not omitting trailing zeros. Our format is always six-digit 0.1 mil or µm resolution (i.e. 001100 = 0.11" or 1.1mm)*/ fprintf (f, "M48\r\n"); fprintf (f, metric ? "METRIC,000.000\r\n" : "INCH\r\n"); for (search = aptr_list->data; search; search = search->next) pcb_fprintf (f, metric ? "T%02dC%.3`mm\r\n" : "T%02dC%.3`mi\r\n", search->dCode, search->width); fprintf (f, "%%\r\n"); /* FIXME */ return 1; } fprintf (f, "G04 start of page %d for group %d idx %d *\r\n", pagecount, group, idx); /* Create a portable timestamp. */ currenttime = time (NULL); { /* avoid gcc complaints */ const char *fmt = "%c UTC"; strftime (utcTime, sizeof utcTime, fmt, gmtime (¤ttime)); } /* Print a cute file header at the beginning of each file. */ fprintf (f, "G04 Title: %s, %s *\r\n", UNKNOWN (PCB->Name), UNKNOWN (name)); fprintf (f, "G04 Creator: %s " VERSION " *\r\n", Progname); fprintf (f, "G04 CreationDate: %s *\r\n", utcTime); #ifdef HAVE_GETPWUID /* ID the user. */ pwentry = getpwuid (getuid ()); fprintf (f, "G04 For: %s *\r\n", pwentry->pw_name); #endif fprintf (f, "G04 Format: Gerber/RS-274X *\r\n"); pcb_fprintf (f, metric ? "G04 PCB-Dimensions (mm): %.2mm %.2mm *\r\n" : "G04 PCB-Dimensions (mil): %.2ml %.2ml *\r\n", PCB->MaxWidth, PCB->MaxHeight); fprintf (f, "G04 PCB-Coordinate-Origin: lower left *\r\n"); /* Signal data in inches. */ fprintf (f, metric ? "%%MOMM*%%\r\n" : "%%MOIN*%%\r\n"); /* Signal Leading zero suppression, Absolute Data, 2.5 format in inch, 4.3 in mm */ fprintf (f, metric ? "%%FSLAX43Y43*%%\r\n" : "%%FSLAX25Y25*%%\r\n"); /* build a legal identifier. */ if (layername) free (layername); layername = strdup (filesuff); if (strrchr (layername, '.')) * strrchr (layername, '.') = 0; for (cp=layername; *cp; cp++) { if (isalnum((int) *cp)) *cp = toupper((int) *cp); else *cp = '_'; } fprintf (f, "%%LN%s*%%\r\n", layername); lncount = 1; for (search = aptr_list->data; search; search = search->next) fprintAperture(f, search); if (aptr_list->count == 0) /* We need to put *something* in the file to make it be parsed as RS-274X instead of RS-274D. */ fprintf (f, "%%ADD11C,0.0100*%%\r\n"); } emit_outline: /* If we're printing a copper layer other than the outline layer, and we want to "print outlines", and we have an outline layer, print the outline layer on this layer also. */ want_outline = 0; if (copy_outline_mode == COPY_OUTLINE_MASK && SL_TYPE (idx) == SL_MASK) want_outline = 1; if (copy_outline_mode == COPY_OUTLINE_SILK && SL_TYPE (idx) == SL_SILK) want_outline = 1; if (copy_outline_mode == COPY_OUTLINE_ALL && (SL_TYPE (idx) == SL_SILK || SL_TYPE (idx) == SL_MASK || SL_TYPE (idx) == SL_FAB || SL_TYPE (idx) == SL_ASSY || SL_TYPE (idx) == 0)) want_outline = 1; if (want_outline && strcmp (name, "outline") && strcmp (name, "route")) { if (outline_layer && outline_layer != PCB->Data->Layer+idx) DrawLayer (outline_layer, ®ion); else if (!outline_layer) { hidGC gc = gui->graphics->make_gc (); printf("name %s idx %d\n", name, idx); if (SL_TYPE (idx) == SL_SILK) gui->graphics->set_line_width (gc, PCB->minSlk); else if (group >= 0) gui->graphics->set_line_width (gc, PCB->minWid); else gui->graphics->set_line_width (gc, AUTO_OUTLINE_WIDTH); gui->graphics->draw_line (gc, 0, 0, PCB->MaxWidth, 0); gui->graphics->draw_line (gc, 0, 0, 0, PCB->MaxHeight); gui->graphics->draw_line (gc, PCB->MaxWidth, 0, PCB->MaxWidth, PCB->MaxHeight); gui->graphics->draw_line (gc, 0, PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight); gui->graphics->destroy_gc (gc); } } return 1; } static hidGC gerber_make_gc (void) { hidGC rv = (hidGC) calloc (1, sizeof (*rv)); rv->cap = Trace_Cap; return rv; } static void gerber_destroy_gc (hidGC gc) { free (gc); } static void gerber_use_mask (enum mask_mode mode) { current_mask = mode; } static void gerber_set_color (hidGC gc, const char *name) { if (strcmp (name, "erase") == 0) { gc->color = 1; gc->erase = 1; gc->drill = 0; } else if (strcmp (name, "drill") == 0) { gc->color = 1; gc->erase = 0; gc->drill = 1; } else { gc->color = 0; gc->erase = 0; gc->drill = 0; } } static void gerber_set_line_cap (hidGC gc, EndCapStyle style) { gc->cap = style; } static void gerber_set_line_width (hidGC gc, Coord width) { gc->width = width; } static void gerber_set_draw_xor (hidGC gc, int xor_) { ; } static void use_gc (hidGC gc, int radius) { if (radius) { radius *= 2; if (radius != linewidth || lastcap != Round_Cap) { Aperture *aptr = findAperture (curr_aptr_list, radius, ROUND); if (aptr == NULL) pcb_fprintf (stderr, "error: aperture for radius %$mS type ROUND is null\n", radius); else if (f && !is_drill) fprintf (f, "G54D%d*", aptr->dCode); linewidth = radius; lastcap = Round_Cap; } } else if (linewidth != gc->width || lastcap != gc->cap) { Aperture *aptr; ApertureShape shape; linewidth = gc->width; lastcap = gc->cap; switch (gc->cap) { case Round_Cap: case Trace_Cap: shape = ROUND; break; default: case Square_Cap: shape = SQUARE; break; } aptr = findAperture (curr_aptr_list, linewidth, shape); if (aptr == NULL) pcb_fprintf (stderr, "error: aperture for width %$mS type %s is null\n", linewidth, shape == ROUND ? "ROUND" : "SQUARE"); else if (f) fprintf (f, "G54D%d*", aptr->dCode); } } static void gerber_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { gerber_draw_line (gc, x1, y1, x1, y2); gerber_draw_line (gc, x1, y1, x2, y1); gerber_draw_line (gc, x1, y2, x2, y2); gerber_draw_line (gc, x2, y1, x2, y2); } static void gerber_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { bool m = false; if (x1 != x2 && y1 != y2 && gc->cap == Square_Cap) { Coord x[5], y[5]; double tx, ty, theta; theta = atan2 (y2-y1, x2-x1); /* T is a vector half a thickness long, in the direction of one of the corners. */ tx = gc->width / 2.0 * cos (theta + M_PI/4) * sqrt(2.0); ty = gc->width / 2.0 * sin (theta + M_PI/4) * sqrt(2.0); x[0] = x1 - tx; y[0] = y1 - ty; x[1] = x2 + ty; y[1] = y2 - tx; x[2] = x2 + tx; y[2] = y2 + ty; x[3] = x1 - ty; y[3] = y1 + tx; x[4] = x[0]; y[4] = y[0]; gerber_fill_polygon (gc, 5, x, y); return; } use_gc (gc, 0); if (!f) return; if (x1 != lastX) { m = true; lastX = x1; print_xcoord (f, PCB, lastX); } if (y1 != lastY) { m = true; lastY = y1; print_ycoord (f, PCB, lastY); } if ((x1 == x2) && (y1 == y2)) fprintf (f, "D03*\r\n"); else { if (m) fprintf (f, "D02*"); if (x2 != lastX) { lastX = x2; print_xcoord (f, PCB, lastX); } if (y2 != lastY) { lastY = y2; print_ycoord (f, PCB, lastY); } fprintf (f, "D01*\r\n"); } } static void gerber_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle) { bool m = false; double arcStartX, arcStopX, arcStartY, arcStopY; /* we never draw zero-width lines */ if (gc->width == 0) return; use_gc (gc, 0); if (!f) return; arcStartX = cx - width * cos (TO_RADIANS (start_angle)); arcStartY = cy + height * sin (TO_RADIANS (start_angle)); /* I checked three different gerber viewers, and they all disagreed on how ellipses should be drawn. The spec just calls G74/G75 "circular interpolation" so there's a chance it just doesn't support ellipses at all. Thus, we draw them out with line segments. Note that most arcs in pcb are circles anyway. */ if (width != height) { double step, angle; Coord max = width > height ? width : height; Coord minr = max - gc->width / 10; int nsteps; Coord x0, y0, x1, y1; if (minr >= max) minr = max - 1; step = acos((double)minr/(double)max) * 180.0/M_PI; if (step > 5) step = 5; nsteps = abs(delta_angle) / step + 1; step = (double)delta_angle / nsteps; x0 = arcStartX; y0 = arcStartY; angle = start_angle; while (nsteps > 0) { nsteps --; x1 = cx - width * cos (TO_RADIANS (angle+step)); y1 = cy + height * sin (TO_RADIANS (angle+step)); gerber_draw_line (gc, x0, y0, x1, y1); x0 = x1; y0 = y1; angle += step; } return; } arcStopX = cx - width * cos (TO_RADIANS (start_angle + delta_angle)); arcStopY = cy + height * sin (TO_RADIANS (start_angle + delta_angle)); if (arcStartX != lastX) { m = true; lastX = arcStartX; print_xcoord (f, PCB, lastX); } if (arcStartY != lastY) { m = true; lastY = arcStartY; print_ycoord (f, PCB, lastY); } if (m) fprintf (f, "D02*"); pcb_fprintf (f, metric ? "G75*G0%1dX%.0muY%.0muI%.0muJ%.0muD01*G01*\r\n" : "G75*G0%1dX%.0mcY%.0mcI%.0mcJ%.0mcD01*G01*\r\n", (delta_angle < 0) ? 2 : 3, gerberX (PCB, arcStopX), gerberY (PCB, arcStopY), gerberXOffset (PCB, cx - arcStartX), gerberYOffset (PCB, cy - arcStartY)); lastX = arcStopX; lastY = arcStopY; } static void gerber_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) { if (radius <= 0) return; if (is_drill) radius = 50 * round (radius / 50.0); use_gc (gc, radius); if (!f) return; if (is_drill) { if (n_pending_drills >= max_pending_drills) { max_pending_drills += 100; pending_drills = (PendingDrills *) realloc(pending_drills, max_pending_drills * sizeof (pending_drills[0])); } pending_drills[n_pending_drills].x = cx; pending_drills[n_pending_drills].y = cy; pending_drills[n_pending_drills].diam = radius * 2; n_pending_drills++; return; } else if (gc->drill && !flash_drills) return; if (cx != lastX) { lastX = cx; print_xcoord (f, PCB, lastX); } if (cy != lastY) { lastY = cy; print_ycoord (f, PCB, lastY); } fprintf (f, "D03*\r\n"); } static void gerber_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) { bool m = false; int i; int firstTime = 1; Coord startX = 0, startY = 0; if (is_mask && current_mask == HID_MASK_BEFORE) return; use_gc (gc, 10 * 100); if (!f) return; fprintf (f, "G36*\r\n"); for (i = 0; i < n_coords; i++) { if (x[i] != lastX) { m = true; lastX = x[i]; print_xcoord (f, PCB, lastX); } if (y[i] != lastY) { m = true; lastY = y[i]; print_ycoord (f, PCB, lastY); } if (firstTime) { firstTime = 0; startX = x[i]; startY = y[i]; if (m) fprintf (f, "D02*"); } else if (m) fprintf (f, "D01*\r\n"); m = false; } if (startX != lastX) { m = true; lastX = startX; print_xcoord (f, PCB, startX); } if (startY != lastY) { m = true; lastY = startY; print_ycoord (f, PCB, lastY); } if (m) fprintf (f, "D01*\r\n"); fprintf (f, "G37*\r\n"); } static void gerber_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { Coord x[5]; Coord y[5]; x[0] = x[4] = x1; y[0] = y[4] = y1; x[1] = x1; y[1] = y2; x[2] = x2; y[2] = y2; x[3] = x2; y[3] = y1; gerber_fill_polygon (gc, 5, x, y); } static void gerber_calibrate (double xval, double yval) { CRASH; } static void gerber_set_crosshair (int x, int y, int action) { } void hid_gerber_init () { memset (&gerber_hid, 0, sizeof (gerber_hid)); memset (&gerber_graphics, 0, sizeof (gerber_graphics)); common_nogui_init (&gerber_hid); common_draw_helpers_init (&gerber_graphics); gerber_hid.struct_size = sizeof (gerber_hid); gerber_hid.name = "gerber"; gerber_hid.description = "RS-274X (Gerber) export"; gerber_hid.exporter = 1; gerber_hid.get_export_options = gerber_get_export_options; gerber_hid.do_export = gerber_do_export; gerber_hid.parse_arguments = gerber_parse_arguments; gerber_hid.set_layer = gerber_set_layer; gerber_hid.calibrate = gerber_calibrate; gerber_hid.set_crosshair = gerber_set_crosshair; gerber_hid.graphics = &gerber_graphics; gerber_graphics.make_gc = gerber_make_gc; gerber_graphics.destroy_gc = gerber_destroy_gc; gerber_graphics.use_mask = gerber_use_mask; gerber_graphics.set_color = gerber_set_color; gerber_graphics.set_line_cap = gerber_set_line_cap; gerber_graphics.set_line_width = gerber_set_line_width; gerber_graphics.set_draw_xor = gerber_set_draw_xor; gerber_graphics.draw_line = gerber_draw_line; gerber_graphics.draw_arc = gerber_draw_arc; gerber_graphics.draw_rect = gerber_draw_rect; gerber_graphics.fill_circle = gerber_fill_circle; gerber_graphics.fill_polygon = gerber_fill_polygon; gerber_graphics.fill_rect = gerber_fill_rect; hid_register_hid (&gerber_hid); } pcb-4.2.2/src/hid/gtk/0000775000076400007640000000000013611113567011422 500000000000000pcb-4.2.2/src/hid/gtk/gui-pinout-window.c0000664000076400007640000000577113434555140015125 00000000000000/* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Contact addresses for paper mail and Email: * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany * Thomas.Nau@rz.uni-ulm.de * */ /* This file written by Bill Wilson for the PCB Gtk port */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "global.h" #include "gui.h" #include "copy.h" #include "data.h" #include "draw.h" #include "mymem.h" #include "move.h" #include "rotate.h" #include "gui-pinout-preview.h" #ifdef HAVE_LIBDMALLOC #include #endif static void pinout_close_cb (GtkWidget * widget, GtkWidget *top_window) { gtk_widget_destroy (top_window); } void ghid_pinout_window_show (GHidPort * out, ElementType * element) { GtkWidget *button, *vbox, *hbox, *preview, *top_window; gchar *title; int width, height; if (!element) return; title = g_strdup_printf ("%s [%s,%s]", UNKNOWN (DESCRIPTION_NAME (element)), UNKNOWN (NAMEONPCB_NAME (element)), UNKNOWN (VALUE_NAME (element))); top_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (top_window), title); g_free (title); gtk_window_set_wmclass (GTK_WINDOW (top_window), "PCB_Pinout", "PCB"); gtk_container_set_border_width (GTK_CONTAINER (top_window), 4); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (top_window), vbox); preview = ghid_pinout_preview_new (element); gtk_box_pack_start (GTK_BOX (vbox), preview, TRUE, TRUE, 0); ghid_pinout_preview_get_natural_size (GHID_PINOUT_PREVIEW (preview), &width, &height); gtk_window_resize (GTK_WINDOW (top_window), width + 50, height + 50); hbox = gtk_hbutton_box_new (); gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); button = gtk_button_new_from_stock (GTK_STOCK_CLOSE); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (pinout_close_cb), top_window); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gtk_widget_realize (top_window); if (Settings.AutoPlace) gtk_window_move (GTK_WINDOW (top_window), 10, 10); gtk_widget_show_all (top_window); } pcb-4.2.2/src/hid/gtk/gtkhid-gl.c0000664000076400007640000014132213533277055013371 00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "crosshair.h" #include "clip.h" #include "../hidint.h" #include "gui.h" #include "gui-pinout-preview.h" /* The Linux OpenGL ABI 1.0 spec requires that we define * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions * in order to get prototypes: * http://www.opengl.org/registry/ABI/ */ #define GL_GLEXT_PROTOTYPES 1 /* This follows autoconf's recommendation for the AX_CHECK_GL macro https://www.gnu.org/software/autoconf-archive/ax_check_gl.html */ #if defined HAVE_WINDOWS_H && defined _WIN32 # include #endif #if defined HAVE_GL_GL_H # include #elif defined HAVE_OPENGL_GL_H # include #else # error autoconf couldnt find gl.h #endif #include #include "hid/common/hidgl.h" #include "hid/common/draw_helpers.h" #include "hid/common/trackball.h" #ifdef HAVE_LIBDMALLOC #include #endif extern HID ghid_hid; extern HID_DRAW ghid_graphics; static hidGC current_gc = NULL; /* Sets gport->u_gc to the "right" GC to use (wrt mask or window) */ #define USE_GC(gc) if (!use_gc(gc)) return static enum mask_mode cur_mask = HID_MASK_OFF; static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}}; static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}}; static int global_view_2d = 1; typedef struct render_priv { GdkGLConfig *glconfig; bool trans_lines; bool in_context; int subcomposite_stencil_bit; char *current_colorname; double current_alpha_mult; GTimer *time_since_expose; /* Feature for leading the user to a particular location */ guint lead_user_timeout; GTimer *lead_user_timer; bool lead_user; Coord lead_user_radius; Coord lead_user_x; Coord lead_user_y; hidGC crosshair_gc; } render_priv; typedef struct hid_gc_struct { HID *me_pointer; const char *colorname; double alpha_mult; Coord width; gint cap, join; } hid_gc_struct; static void draw_lead_user (render_priv *priv); static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y); static void start_subcomposite (void) { render_priv *priv = gport->render_priv; int stencil_bit; /* Flush out any existing geoemtry to be rendered */ hidgl_flush_triangles (&buffer); glEnable (GL_STENCIL_TEST); /* Enable Stencil test */ glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */ stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */ glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */ glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */ priv->subcomposite_stencil_bit = stencil_bit; } static void end_subcomposite (void) { render_priv *priv = gport->render_priv; /* Flush out any existing geoemtry to be rendered */ hidgl_flush_triangles (&buffer); hidgl_return_stencil_bit (priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */ glStencilMask (0); glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */ glDisable (GL_STENCIL_TEST); /* Disable Stencil test */ priv->subcomposite_stencil_bit = 0; } int ghid_set_layer (const char *name, int group, int empty) { render_priv *priv = gport->render_priv; int idx = group; if (idx >= 0 && idx < max_group) { int n = PCB->LayerGroups.Number[group]; for (idx = 0; idx < n-1; idx ++) { int ni = PCB->LayerGroups.Entries[group][idx]; if (ni >= 0 && ni < max_copper_layer + SILK_LAYER && PCB->Data->Layer[ni].On) break; } idx = PCB->LayerGroups.Entries[group][idx]; } end_subcomposite (); start_subcomposite (); if (idx >= 0 && idx < max_copper_layer + SILK_LAYER) { priv->trans_lines = true; return PCB->Data->Layer[idx].On; } if (idx < 0) { switch (SL_TYPE (idx)) { case SL_INVISIBLE: return PCB->InvisibleObjectsOn; case SL_MASK: if (SL_MYSIDE (idx)) return TEST_FLAG (SHOWMASKFLAG, PCB); return 0; case SL_SILK: priv->trans_lines = true; if (SL_MYSIDE (idx)) return PCB->ElementOn; return 0; case SL_ASSY: return 0; case SL_PDRILL: case SL_UDRILL: return 1; case SL_RATS: if (PCB->RatOn) priv->trans_lines = true; return PCB->RatOn; } } return 0; } static void ghid_end_layer (void) { end_subcomposite (); } void ghid_destroy_gc (hidGC gc) { g_free (gc); } hidGC ghid_make_gc (void) { hidGC rv; rv = g_new0 (hid_gc_struct, 1); rv->me_pointer = &ghid_hid; rv->colorname = Settings.BackgroundColor; rv->alpha_mult = 1.0; return rv; } void ghid_draw_grid (BoxType *drawn_area) { if (Vz (PCB->Grid) < MIN_GRID_DISTANCE) return; if (gdk_color_parse (Settings.GridColor, &gport->grid_color)) { gport->grid_color.red ^= gport->bg_color.red; gport->grid_color.green ^= gport->bg_color.green; gport->grid_color.blue ^= gport->bg_color.blue; } glEnable (GL_COLOR_LOGIC_OP); glLogicOp (GL_XOR); glColor3f (gport->grid_color.red / 65535., gport->grid_color.green / 65535., gport->grid_color.blue / 65535.); hidgl_draw_grid (drawn_area); glDisable (GL_COLOR_LOGIC_OP); } static void ghid_draw_bg_image (void) { static GLuint texture_handle = 0; if (!ghidgui->bg_pixbuf) return; if (texture_handle == 0) { int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf); int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf); int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf); int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf); int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf); unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf); g_warn_if_fail (bits_per_sample == 8); g_warn_if_fail (rowstride == width * n_channels); glGenTextures (1, &texture_handle); glBindTexture (GL_TEXTURE_2D, texture_handle); /* XXX: We should proabbly determine what the maxmimum texture supported is, * and if our image is larger, shrink it down using GDK pixbuf routines * rather than having it fail below. */ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels); } glBindTexture (GL_TEXTURE_2D, texture_handle); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glEnable (GL_TEXTURE_2D); /* Render a quad with the background as a texture */ glBegin (GL_QUADS); glTexCoord2d (0., 0.); glVertex3i (0, 0, 0); glTexCoord2d (1., 0.); glVertex3i (PCB->MaxWidth, 0, 0); glTexCoord2d (1., 1.); glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0); glTexCoord2d (0., 1.); glVertex3i (0, PCB->MaxHeight, 0); glEnd (); glDisable (GL_TEXTURE_2D); } void ghid_use_mask (enum mask_mode mode) { static int stencil_bit = 0; if (mode == cur_mask) return; /* Flush out any existing geoemtry to be rendered */ hidgl_flush_triangles (&buffer); switch (mode) { case HID_MASK_BEFORE: /* The HID asks not to receive this mask type, so warn if we get it */ g_return_if_reached (); case HID_MASK_CLEAR: /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */ glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */ glEnable (GL_STENCIL_TEST); /* Enable Stencil test */ stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */ glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */ glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */ glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */ break; case HID_MASK_AFTER: /* Drawing operations as masked to areas where the stencil buffer is '0' */ glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */ glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */ glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */ break; case HID_MASK_OFF: /* Disable stenciling */ hidgl_return_stencil_bit (stencil_bit); /* Relinquish any bitplane we previously used */ glDisable (GL_STENCIL_TEST); /* Disable Stencil test */ break; } cur_mask = mode; } /* Config helper functions for when the user changes color preferences. | set_special colors used in the gtkhid. */ static void set_special_grid_color (void) { if (!gport->colormap) return; gport->grid_color.red ^= gport->bg_color.red; gport->grid_color.green ^= gport->bg_color.green; gport->grid_color.blue ^= gport->bg_color.blue; } void ghid_set_special_colors (HID_Attribute * ha) { if (!ha->name || !ha->value) return; if (!strcmp (ha->name, "background-color")) { ghid_map_color_string (*(char **) ha->value, &gport->bg_color); set_special_grid_color (); } else if (!strcmp (ha->name, "off-limit-color")) { ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color); } else if (!strcmp (ha->name, "grid-color")) { ghid_map_color_string (*(char **) ha->value, &gport->grid_color); set_special_grid_color (); } } typedef struct { int color_set; GdkColor color; double red; double green; double blue; } ColorCache; static void set_gl_color_for_gc (hidGC gc) { render_priv *priv = gport->render_priv; static void *cache = NULL; hidval cval; ColorCache *cc; double r, g, b, a; if (priv->current_colorname != NULL && strcmp (priv->current_colorname, gc->colorname) == 0 && priv->current_alpha_mult == gc->alpha_mult) return; free (priv->current_colorname); priv->current_colorname = strdup (gc->colorname); priv->current_alpha_mult = gc->alpha_mult; if (gport->colormap == NULL) gport->colormap = gtk_widget_get_colormap (gport->top_window); if (strcmp (gc->colorname, "erase") == 0) { r = gport->bg_color.red / 65535.; g = gport->bg_color.green / 65535.; b = gport->bg_color.blue / 65535.; a = 1.0; } else if (strcmp (gc->colorname, "drill") == 0) { r = gport->offlimits_color.red / 65535.; g = gport->offlimits_color.green / 65535.; b = gport->offlimits_color.blue / 65535.; a = 0.85; } else { if (hid_cache_color (0, gc->colorname, &cval, &cache)) cc = (ColorCache *) cval.ptr; else { cc = (ColorCache *) malloc (sizeof (ColorCache)); memset (cc, 0, sizeof (*cc)); cval.ptr = cc; hid_cache_color (1, gc->colorname, &cval, &cache); } if (!cc->color_set) { if (gdk_color_parse (gc->colorname, &cc->color)) gdk_color_alloc (gport->colormap, &cc->color); else gdk_color_white (gport->colormap, &cc->color); cc->red = cc->color.red / 65535.; cc->green = cc->color.green / 65535.; cc->blue = cc->color.blue / 65535.; cc->color_set = 1; } r = cc->red; g = cc->green; b = cc->blue; a = 0.7; } if (1) { double maxi, mult; a *= gc->alpha_mult; if (!priv->trans_lines) a = 1.0; maxi = r; if (g > maxi) maxi = g; if (b > maxi) maxi = b; mult = MIN (1 / a, 1 / maxi); #if 1 r = r * mult; g = g * mult; b = b * mult; #endif } if(!priv->in_context) return; hidgl_flush_triangles (&buffer); glColor4d (r, g, b, a); } void ghid_set_color (hidGC gc, const char *name) { gc->colorname = name; set_gl_color_for_gc (gc); } void ghid_set_alpha_mult (hidGC gc, double alpha_mult) { gc->alpha_mult = alpha_mult; set_gl_color_for_gc (gc); } void ghid_set_line_cap (hidGC gc, EndCapStyle style) { gc->cap = style; } void ghid_set_line_width (hidGC gc, Coord width) { gc->width = width; } void ghid_set_draw_xor (hidGC gc, int xor) { /* NOT IMPLEMENTED */ /* Only presently called when setting up a crosshair GC. * We manage our own drawing model for that anyway. */ } void ghid_set_draw_faded (hidGC gc, int faded) { printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded); } void ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { printf ("ghid_set_line_cap_angle() -- not implemented\n"); } static void ghid_invalidate_current_gc (void) { current_gc = NULL; } static int use_gc (hidGC gc) { if (gc->me_pointer != &ghid_hid) { fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n"); abort (); } if (current_gc == gc) return 1; current_gc = gc; set_gl_color_for_gc (gc); return 1; } void ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { USE_GC (gc); hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->view.coord_per_px); } void ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius, Angle start_angle, Angle delta_angle) { USE_GC (gc); hidgl_draw_arc (gc->width, cx, cy, xradius, yradius, start_angle, delta_angle, gport->view.coord_per_px); } void ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { USE_GC (gc); hidgl_draw_rect (x1, y1, x2, y2); } void ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) { USE_GC (gc); hidgl_fill_circle (cx, cy, radius, gport->view.coord_per_px); } void ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) { USE_GC (gc); hidgl_fill_polygon (n_coords, x, y); } void ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box) { USE_GC (gc); hidgl_fill_pcb_polygon (poly, clip_box, gport->view.coord_per_px); } void ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box) { common_thindraw_pcb_polygon (gc, poly, clip_box); ghid_set_alpha_mult (gc, 0.25); gui->graphics->fill_pcb_polygon (gc, poly, clip_box); ghid_set_alpha_mult (gc, 1.0); } void ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) { USE_GC (gc); hidgl_fill_rect (x1, y1, x2, y2); } void ghid_invalidate_lr (Coord left, Coord right, Coord top, Coord bottom) { ghid_invalidate_all (); } #define MAX_ELAPSED (50. / 1000.) /* 50ms */ void ghid_invalidate_all () { render_priv *priv = gport->render_priv; double elapsed = g_timer_elapsed (priv->time_since_expose, NULL); ghid_draw_area_update (gport, NULL); if (elapsed > MAX_ELAPSED) gdk_window_process_all_updates (); } void ghid_notify_crosshair_change (bool changes_complete) { /* We sometimes get called before the GUI is up */ if (gport->drawing_area == NULL) return; /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */ if (changes_complete) ghid_invalidate_all (); } void ghid_notify_mark_change (bool changes_complete) { /* We sometimes get called before the GUI is up */ if (gport->drawing_area == NULL) return; /* FIXME: We could just invalidate the bounds of the mark? */ if (changes_complete) ghid_invalidate_all (); } static void draw_right_cross (gint x, gint y, gint z) { glVertex3i (x, 0, z); glVertex3i (x, PCB->MaxHeight, z); glVertex3i (0, y, z); glVertex3i (PCB->MaxWidth, y, z); } static void draw_slanted_cross (gint x, gint y, gint z) { gint x0, y0, x1, y1; x0 = x + (PCB->MaxHeight - y); x0 = MAX(0, MIN (x0, PCB->MaxWidth)); x1 = x - y; x1 = MAX(0, MIN (x1, PCB->MaxWidth)); y0 = y + (PCB->MaxWidth - x); y0 = MAX(0, MIN (y0, PCB->MaxHeight)); y1 = y - x; y1 = MAX(0, MIN (y1, PCB->MaxHeight)); glVertex3i (x0, y0, z); glVertex3i (x1, y1, z); x0 = x - (PCB->MaxHeight - y); x0 = MAX(0, MIN (x0, PCB->MaxWidth)); x1 = x + y; x1 = MAX(0, MIN (x1, PCB->MaxWidth)); y0 = y + x; y0 = MAX(0, MIN (y0, PCB->MaxHeight)); y1 = y - (PCB->MaxWidth - x); y1 = MAX(0, MIN (y1, PCB->MaxHeight)); glVertex3i (x0, y0, z); glVertex3i (x1, y1, z); } static void draw_dozen_cross (gint x, gint y, gint z) { gint x0, y0, x1, y1; gdouble tan60 = sqrt (3); x0 = x + (PCB->MaxHeight - y) / tan60; x0 = MAX(0, MIN (x0, PCB->MaxWidth)); x1 = x - y / tan60; x1 = MAX(0, MIN (x1, PCB->MaxWidth)); y0 = y + (PCB->MaxWidth - x) * tan60; y0 = MAX(0, MIN (y0, PCB->MaxHeight)); y1 = y - x * tan60; y1 = MAX(0, MIN (y1, PCB->MaxHeight)); glVertex3i (x0, y0, z); glVertex3i (x1, y1, z); x0 = x + (PCB->MaxHeight - y) * tan60; x0 = MAX(0, MIN (x0, PCB->MaxWidth)); x1 = x - y * tan60; x1 = MAX(0, MIN (x1, PCB->MaxWidth)); y0 = y + (PCB->MaxWidth - x) / tan60; y0 = MAX(0, MIN (y0, PCB->MaxHeight)); y1 = y - x / tan60; y1 = MAX(0, MIN (y1, PCB->MaxHeight)); glVertex3i (x0, y0, z); glVertex3i (x1, y1, z); x0 = x - (PCB->MaxHeight - y) / tan60; x0 = MAX(0, MIN (x0, PCB->MaxWidth)); x1 = x + y / tan60; x1 = MAX(0, MIN (x1, PCB->MaxWidth)); y0 = y + x * tan60; y0 = MAX(0, MIN (y0, PCB->MaxHeight)); y1 = y - (PCB->MaxWidth - x) * tan60; y1 = MAX(0, MIN (y1, PCB->MaxHeight)); glVertex3i (x0, y0, z); glVertex3i (x1, y1, z); x0 = x - (PCB->MaxHeight - y) * tan60; x0 = MAX(0, MIN (x0, PCB->MaxWidth)); x1 = x + y * tan60; x1 = MAX(0, MIN (x1, PCB->MaxWidth)); y0 = y + x / tan60; y0 = MAX(0, MIN (y0, PCB->MaxHeight)); y1 = y - (PCB->MaxWidth - x) / tan60; y1 = MAX(0, MIN (y1, PCB->MaxHeight)); glVertex3i (x0, y0, z); glVertex3i (x1, y1, z); } static void draw_crosshair (render_priv *priv) { gint x, y, z; static int done_once = 0; static GdkColor cross_color; if (!done_once) { done_once = 1; /* FIXME: when CrossColor changed from config */ ghid_map_color_string (Settings.CrossColor, &cross_color); } x = gport->crosshair_x; y = gport->crosshair_y; z = 0; glEnable (GL_COLOR_LOGIC_OP); glLogicOp (GL_XOR); glColor3f (cross_color.red / 65535., cross_color.green / 65535., cross_color.blue / 65535.); glBegin (GL_LINES); draw_right_cross (x, y, z); if (Crosshair.shape == Union_Jack_Crosshair_Shape) draw_slanted_cross (x, y, z); if (Crosshair.shape == Dozen_Crosshair_Shape) draw_dozen_cross (x, y, z); glEnd (); glDisable (GL_COLOR_LOGIC_OP); } void ghid_init_renderer (int *argc, char ***argv, GHidPort *port) { render_priv *priv; port->render_priv = priv = g_new0 (render_priv, 1); port->render_priv->crosshair_gc = gui->graphics->make_gc (); priv->time_since_expose = g_timer_new (); gtk_gl_init(argc, argv); /* setup GL-context */ priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA | GDK_GL_MODE_STENCIL | GDK_GL_MODE_DOUBLE); if (!priv->glconfig) { printf ("Could not setup GL-context!\n"); return; /* Should we abort? */ } /* Setup HID function pointers specific to the GL renderer*/ ghid_hid.end_layer = ghid_end_layer; ghid_graphics.fill_pcb_polygon = ghid_fill_pcb_polygon; ghid_graphics.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon; } void ghid_shutdown_renderer (GHidPort *port) { render_priv *priv = port->render_priv; gui->graphics->destroy_gc (priv->crosshair_gc); ghid_cancel_lead_user (); g_free (port->render_priv); port->render_priv = NULL; } void ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port) { render_priv *priv = port->render_priv; gtk_widget_set_gl_capability (widget, priv->glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); } void ghid_drawing_area_configure_hook (GHidPort *port) { } gboolean ghid_start_drawing (GHidPort *port, GtkWidget *widget) { GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget); GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget); /* make GL-context "current" */ if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) return FALSE; port->render_priv->in_context = true; return TRUE; } void ghid_end_drawing (GHidPort *port, GtkWidget *widget) { GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget); if (gdk_gl_drawable_is_double_buffered (pGlDrawable)) gdk_gl_drawable_swap_buffers (pGlDrawable); else glFlush (); port->render_priv->in_context = false; /* end drawing to current GL-context */ gdk_gl_drawable_gl_end (pGlDrawable); } void ghid_screen_update (void) { } #define Z_NEAR 3.0 gboolean ghid_drawing_area_expose_cb (GtkWidget *widget, GdkEventExpose *ev, GHidPort *port) { render_priv *priv = port->render_priv; GtkAllocation allocation; BoxType region; Coord min_x, min_y; Coord max_x, max_y; Coord new_x, new_y; Coord min_depth; Coord max_depth; gtk_widget_get_allocation (widget, &allocation); ghid_start_drawing (port, widget); hidgl_start_render (); /* If we don't have any stencil bits available, we can't use the hidgl polygon drawing routine */ /* TODO: We could use the GLU tessellator though */ if (hidgl_stencil_bits() == 0) ghid_graphics.fill_pcb_polygon = common_fill_pcb_polygon; glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glViewport (0, 0, allocation.width, allocation.height); glEnable (GL_SCISSOR_TEST); glScissor (ev->area.x, allocation.height - ev->area.height - ev->area.y, ev->area.width, ev->area.height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0); glMultMatrixf ((GLfloat *)view_matrix); glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0); glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px, (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px, ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px); glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth : -port->view.x0, port->view.flip_y ? port->view.y0 - PCB->MaxHeight : -port->view.y0, 0); glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix); glEnable (GL_STENCIL_TEST); glClearColor (port->offlimits_color.red / 65535., port->offlimits_color.green / 65535., port->offlimits_color.blue / 65535., 1.); glStencilMask (~0); glClearStencil (0); glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); hidgl_reset_stencil_usage (); /* Disable the stencil test until we need it - otherwise it gets dirty */ glDisable (GL_STENCIL_TEST); glStencilMask (0); glStencilFunc (GL_ALWAYS, 0, 0); /* Test the 8 corners of a cube spanning the event */ min_depth = -50; /* FIXME */ max_depth = 0; /* FIXME */ ghid_unproject_to_z_plane (ev->area.x, ev->area.y, min_depth, &new_x, &new_y); max_x = min_x = new_x; max_y = min_y = new_y; ghid_unproject_to_z_plane (ev->area.x, ev->area.y, max_depth, &new_x, &new_y); min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); /* */ ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y, min_depth, &new_x, &new_y); min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y, max_depth, &new_x, &new_y); min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); /* */ ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y + ev->area.height, min_depth, &new_x, &new_y); min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y + ev->area.height, max_depth, &new_x, &new_y); min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); /* */ ghid_unproject_to_z_plane (ev->area.x, ev->area.y + ev->area.height, min_depth, &new_x, &new_y); min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); ghid_unproject_to_z_plane (ev->area.x, ev->area.y + ev->area.height, max_depth, &new_x, &new_y); min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); region.X1 = min_x; region.X2 = max_x + 1; region.Y1 = min_y; region.Y2 = max_y + 1; region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1)); region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2)); region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1)); region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2)); glColor3f (port->bg_color.red / 65535., port->bg_color.green / 65535., port->bg_color.blue / 65535.); glBegin (GL_QUADS); glVertex3i (0, 0, -50); glVertex3i (PCB->MaxWidth, 0, -50); glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50); glVertex3i (0, PCB->MaxHeight, -50); glEnd (); ghid_draw_bg_image (); ghid_invalidate_current_gc (); hid_expose_callback (&ghid_hid, ®ion, 0); hidgl_flush_triangles (&buffer); ghid_graphics.draw_grid (®ion); ghid_invalidate_current_gc (); DrawAttached (priv->crosshair_gc); DrawMark (priv->crosshair_gc); hidgl_flush_triangles (&buffer); draw_crosshair (priv); hidgl_flush_triangles (&buffer); draw_lead_user (priv); hidgl_finish_render (); ghid_end_drawing (port, widget); g_timer_start (priv->time_since_expose); return FALSE; } /* This realize callback is used to work around a crash bug in some mesa * versions (observed on a machine running the intel i965 driver. It isn't * obvious why it helps, but somehow fiddling with the GL context here solves * the issue. The problem appears to have been fixed in recent mesa versions. */ void ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data) { GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) return; gdk_gl_drawable_gl_end (gldrawable); return; } gboolean ghid_pinout_preview_expose (GtkWidget *widget, GdkEventExpose *ev) { GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget); GtkAllocation allocation; view_data save_view; int save_width, save_height; Coord save_max_width; Coord save_max_height; double xz, yz; save_view = gport->view; save_width = gport->width; save_height = gport->height; save_max_width = PCB->MaxWidth; save_max_height = PCB->MaxHeight; /* Setup zoom factor for drawing routines */ gtk_widget_get_allocation (widget, &allocation); xz = (double) pinout->x_max / allocation.width; yz = (double) pinout->y_max / allocation.height; if (xz > yz) gport->view.coord_per_px = xz; else gport->view.coord_per_px = yz; gport->width = allocation.width; gport->height = allocation.height; gport->view.width = allocation.width * gport->view.coord_per_px; gport->view.height = allocation.height * gport->view.coord_per_px; gport->view.x0 = (pinout->x_max - gport->view.width) / 2; gport->view.y0 = (pinout->y_max - gport->view.height) / 2; PCB->MaxWidth = pinout->x_max; PCB->MaxHeight = pinout->y_max; ghid_start_drawing (gport, widget); hidgl_start_render (); #if 0 /* We disable alpha blending here, as hid_expose_callback() does not * call set_layer() as appropriate for us to sub-composite rendering * from each layer when drawing a single element. If we leave alpha- * blending on, it means text and overlapping pads are rendered ugly. */ glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif glViewport (0, 0, allocation.width, allocation.height); #if 0 /* We disable the scissor test here, as it is interacting badly with * being handed expose events which don't cover the whole window. * As we have a double-buffered GL window, we end up with unintialised * contents remaining in the unpainted areas (outside the scissor * region), and these are being flipped onto the screen. * * The debugging code below shows multiple expose events when the * window is shown the first time, some of which are very small. * * XXX: There is clearly a perforamnce issue here, in that we may * be rendering the preview more times, and over a larger area * than is really required. */ glEnable (GL_SCISSOR_TEST); glScissor (ev->area.x, allocation.height - ev->area.height - ev->area.y, ev->area.width, ev->area.height); #endif #ifdef DEBUG printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n", ev->area.x, ev->area.y, ev->area.width, ev->area.height, (double)ev->area.x, (double)(allocation.height - ev->area.height - ev->area.y), (double)ev->area.width, (double)ev->area.height); #endif glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0.0f, 0.0f, -Z_NEAR); glClearColor (gport->bg_color.red / 65535., gport->bg_color.green / 65535., gport->bg_color.blue / 65535., 1.); glStencilMask (~0); glClearStencil (0); glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); hidgl_reset_stencil_usage (); /* Disable the stencil test until we need it - otherwise it gets dirty */ glDisable (GL_STENCIL_TEST); glStencilMask (0); glStencilFunc (GL_ALWAYS, 0, 0); /* call the drawing routine */ ghid_invalidate_current_gc (); glPushMatrix (); glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px, (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px, ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px); glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth : -gport->view.x0, gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight : -gport->view.y0, 0); hid_expose_callback (&ghid_hid, NULL, pinout->element); hidgl_flush_triangles (&buffer); glPopMatrix (); hidgl_finish_render (); ghid_end_drawing (gport, widget); gport->view = save_view; gport->width = save_width; gport->height = save_height; PCB->MaxWidth = save_max_width; PCB->MaxHeight = save_max_height; return FALSE; } GdkPixmap * ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth) { GdkGLConfig *glconfig; GdkPixmap *pixmap; GdkGLPixmap *glpixmap; GdkGLContext* glcontext; GdkGLDrawable* gldrawable; view_data save_view; int save_width, save_height; BoxType region; save_view = gport->view; save_width = gport->width; save_height = gport->height; /* Setup rendering context for drawing routines */ glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB | GDK_GL_MODE_STENCIL | GDK_GL_MODE_SINGLE); pixmap = gdk_pixmap_new (NULL, width, height, depth); glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL); gldrawable = GDK_GL_DRAWABLE (glpixmap); glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE); /* Setup zoom factor for drawing routines */ gport->view.coord_per_px = zoom; gport->width = width; gport->height = height; gport->view.width = width * gport->view.coord_per_px; gport->view.height = height * gport->view.coord_per_px; gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx; gport->view.x0 -= gport->view.height / 2; gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy; gport->view.y0 -= gport->view.width / 2; /* make GL-context "current" */ if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) { return NULL; } hidgl_start_render (); gport->render_priv->in_context = true; glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glViewport (0, 0, width, height); glEnable (GL_SCISSOR_TEST); glScissor (0, 0, width, height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, width, height, 0, -100000, 100000); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0.0f, 0.0f, -Z_NEAR); glClearColor (gport->bg_color.red / 65535., gport->bg_color.green / 65535., gport->bg_color.blue / 65535., 1.); glStencilMask (~0); glClearStencil (0); glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); hidgl_reset_stencil_usage (); /* Disable the stencil test until we need it - otherwise it gets dirty */ glDisable (GL_STENCIL_TEST); glStencilMask (0); glStencilFunc (GL_ALWAYS, 0, 0); /* call the drawing routine */ ghid_invalidate_current_gc (); glPushMatrix (); glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px, (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px, ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px); glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth : -gport->view.x0, gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight : -gport->view.y0, 0); region.X1 = MIN(Px(0), Px(gport->width + 1)); region.Y1 = MIN(Py(0), Py(gport->height + 1)); region.X2 = MAX(Px(0), Px(gport->width + 1)); region.Y2 = MAX(Py(0), Py(gport->height + 1)); region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1)); region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2)); region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1)); region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2)); hid_expose_callback (&ghid_hid, ®ion, NULL); hidgl_flush_triangles (&buffer); glPopMatrix (); glFlush (); hidgl_finish_render (); /* end drawing to current GL-context */ gport->render_priv->in_context = false; gdk_gl_drawable_gl_end (gldrawable); gdk_pixmap_unset_gl_capability (pixmap); g_object_unref (glconfig); g_object_unref (glcontext); gport->view = save_view; gport->width = save_width; gport->height = save_height; return pixmap; } HID_DRAW * ghid_request_debug_draw (void) { GHidPort *port = gport; GtkWidget *widget = port->drawing_area; GtkAllocation allocation; gtk_widget_get_allocation (widget, &allocation); ghid_start_drawing (port, widget); hidgl_start_render (); glViewport (0, 0, allocation.width, allocation.height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, allocation.width, allocation.height, 0, 0, 100); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0.0f, 0.0f, -Z_NEAR); ghid_invalidate_current_gc (); /* Setup stenciling */ glDisable (GL_STENCIL_TEST); glPushMatrix (); glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px, (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px, ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px); glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth : -port->view.x0, port->view.flip_y ? port->view.y0 - PCB->MaxHeight : -port->view.y0, 0); return ghid_hid.graphics; } void ghid_flush_debug_draw (void) { GtkWidget *widget = gport->drawing_area; GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget); hidgl_flush_triangles (&buffer); if (gdk_gl_drawable_is_double_buffered (pGlDrawable)) gdk_gl_drawable_swap_buffers (pGlDrawable); else glFlush (); } void ghid_finish_debug_draw (void) { hidgl_flush_triangles (&buffer); glPopMatrix (); hidgl_finish_render (); ghid_end_drawing (gport, gport->drawing_area); } static float determinant_2x2 (float m[2][2]) { float det; det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; return det; } #if 0 static float determinant_4x4 (float m[4][4]) { float det; det = m[0][3] * m[1][2] * m[2][1] * m[3][0]-m[0][2] * m[1][3] * m[2][1] * m[3][0] - m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] + m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] - m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] + m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] - m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] + m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] - m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] + m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] - m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] + m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] - m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3]; return det; } #endif static void invert_2x2 (float m[2][2], float out[2][2]) { float scale = 1 / determinant_2x2 (m); out[0][0] = m[1][1] * scale; out[0][1] = -m[0][1] * scale; out[1][0] = -m[1][0] * scale; out[1][1] = m[0][0] * scale; } #if 0 static void invert_4x4 (float m[4][4], float out[4][4]) { float scale = 1 / determinant_4x4 (m); out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] + m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] - m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale; out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] - m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] + m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale; out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] + m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] - m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale; out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] - m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] + m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale; out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] - m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] + m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale; out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] + m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] - m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale; out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] - m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] + m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale; out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] + m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] - m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale; out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] + m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] - m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale; out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] - m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] + m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale; out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] + m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] - m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale; out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] - m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] + m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale; out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] - m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] + m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale; out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] + m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] - m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale; out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] - m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] + m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale; out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] + m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale; } #endif static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y) { float mat[2][2]; float inv_mat[2][2]; float x, y; /* ex = view_matrix[0][0] * vx + view_matrix[0][1] * vy + view_matrix[0][2] * vz + view_matrix[0][3] * 1; ey = view_matrix[1][0] * vx + view_matrix[1][1] * vy + view_matrix[1][2] * vz + view_matrix[1][3] * 1; UNKNOWN ez = view_matrix[2][0] * vx + view_matrix[2][1] * vy + view_matrix[2][2] * vz + view_matrix[2][3] * 1; ex - view_matrix[0][3] * 1 - view_matrix[0][2] * vz = view_matrix[0][0] * vx + view_matrix[0][1] * vy; ey - view_matrix[1][3] * 1 - view_matrix[1][2] * vz = view_matrix[1][0] * vx + view_matrix[1][1] * vy; */ /* NB: last_modelview_matrix is transposed in memory! */ x = (float)ex - last_modelview_matrix[3][0] * 1 - last_modelview_matrix[2][0] * pcb_z; y = (float)ey - last_modelview_matrix[3][1] * 1 - last_modelview_matrix[2][1] * pcb_z; /* x = view_matrix[0][0] * vx + view_matrix[0][1] * vy; y = view_matrix[1][0] * vx + view_matrix[1][1] * vy; [view_matrix[0][0] view_matrix[0][1]] [vx] = [x] [view_matrix[1][0] view_matrix[1][1]] [vy] [y] */ mat[0][0] = last_modelview_matrix[0][0]; mat[0][1] = last_modelview_matrix[1][0]; mat[1][0] = last_modelview_matrix[0][1]; mat[1][1] = last_modelview_matrix[1][1]; /* if (determinant_2x2 (mat) < 0.00001) */ /* printf ("Determinant is quite small\n"); */ invert_2x2 (mat, inv_mat); *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y); *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y); } bool ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y) { ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y); return true; } bool ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y) { /* NB: last_modelview_matrix is transposed in memory */ float w = last_modelview_matrix[0][3] * (float)pcb_x + last_modelview_matrix[1][3] * (float)pcb_y + last_modelview_matrix[2][3] * 0. + last_modelview_matrix[3][3] * 1.; *event_x = (last_modelview_matrix[0][0] * (float)pcb_x + last_modelview_matrix[1][0] * (float)pcb_y + last_modelview_matrix[2][0] * 0. + last_modelview_matrix[3][0] * 1.) / w; *event_y = (last_modelview_matrix[0][1] * (float)pcb_x + last_modelview_matrix[1][1] * (float)pcb_y + last_modelview_matrix[2][1] * 0. + last_modelview_matrix[3][1] * 1.) / w; return true; } void ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata) { global_view_2d = view_2d; ghid_invalidate_all (); } void ghid_port_rotate (void *ball, float *quarternion, gpointer userdata) { #ifdef DEBUG_ROTATE int row, column; #endif build_rotmatrix (view_matrix, quarternion); #ifdef DEBUG_ROTATE for (row = 0; row < 4; row++) { printf ("[ %f", view_matrix[row][0]); for (column = 1; column < 4; column++) { printf (",\t%f", view_matrix[row][column]); } printf ("\t]\n"); } printf ("\n"); #endif ghid_invalidate_all (); } #define LEAD_USER_WIDTH 0.2 /* millimeters */ #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */ #define LEAD_USER_VELOCITY 3. /* millimeters per second */ #define LEAD_USER_ARC_COUNT 3 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */ #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */ #define LEAD_USER_COLOR_R 1. #define LEAD_USER_COLOR_G 1. #define LEAD_USER_COLOR_B 0. static void draw_lead_user (render_priv *priv) { int i; double radius = priv->lead_user_radius; double width = MM_TO_COORD (LEAD_USER_WIDTH); double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION); if (!priv->lead_user) return; glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT); glEnable (GL_COLOR_LOGIC_OP); glLogicOp (GL_XOR); glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B); /* arcs at the approrpriate radii */ for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation) { if (radius < width) radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); /* Draw an arc at radius */ hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y, radius, radius, 0, 360, gport->view.coord_per_px); } hidgl_flush_triangles (&buffer); glPopAttrib (); } gboolean lead_user_cb (gpointer data) { render_priv *priv = data; Coord step; double elapsed_time; /* Queue a redraw */ ghid_invalidate_all (); /* Update radius */ elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL); g_timer_start (priv->lead_user_timer); step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time); if (priv->lead_user_radius > step) priv->lead_user_radius -= step; else priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); return TRUE; } void ghid_lead_user_to_location (Coord x, Coord y) { render_priv *priv = gport->render_priv; ghid_cancel_lead_user (); priv->lead_user = true; priv->lead_user_x = x; priv->lead_user_y = y; priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv); priv->lead_user_timer = g_timer_new (); } void ghid_cancel_lead_user (void) { render_priv *priv = gport->render_priv; if (priv->lead_user_timeout) g_source_remove (priv->lead_user_timeout); if (priv->lead_user_timer) g_timer_destroy (priv->lead_user_timer); if (priv->lead_user) ghid_invalidate_all (); priv->lead_user_timeout = 0; priv->lead_user_timer = NULL; priv->lead_user = false; } pcb-4.2.2/src/hid/gtk/gui-utils.c0000664000076400007640000005517513607705030013442 00000000000000/* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 1994,1995,1996 Thomas Nau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ /* This module, gui-utils.c, was written by Bill Wilson and the functions * here are Copyright (C) 2004 by Bill Wilson. These functions are utility * functions which are taken from my other GPL'd projects gkrellm and * gstocks and are copied here for the Gtk PCB port. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gui.h" #include #ifdef HAVE_LIBDMALLOC #include #endif /* Not a gui function, but no better place to put it... */ gboolean dup_string (gchar ** dst, const gchar * src) { if ((dst == NULL) || ((*dst == NULL) && (src == NULL))) return FALSE; if (*dst) { if (src && !strcmp (*dst, src)) return FALSE; g_free (*dst); } *dst = g_strdup (src); return TRUE; } void free_glist_and_data (GList ** list_head) { GList *list; if (*list_head == NULL) return; for (list = *list_head; list; list = list->next) if (list->data) g_free (list->data); g_list_free (*list_head); *list_head = NULL; } gboolean ghid_is_modifier_key_sym (gint ksym) { if (ksym == GDK_Shift_R || ksym == GDK_Shift_L || ksym == GDK_Control_R || ksym == GDK_Control_L) return TRUE; return FALSE; } ModifierKeysState ghid_modifier_keys_state (GdkModifierType * state) { GdkModifierType mask; ModifierKeysState mk; gboolean shift, control, mod1; GHidPort *out = &ghid_port; if (!state) gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area), NULL, NULL, &mask); else mask = *state; shift = (mask & GDK_SHIFT_MASK); control = (mask & GDK_CONTROL_MASK); mod1 = (mask & GDK_MOD1_MASK); if (shift && !control && !mod1) mk = SHIFT_PRESSED; else if (!shift && control && !mod1) mk = CONTROL_PRESSED; else if (!shift && !control && mod1) mk = MOD1_PRESSED; else if (shift && control && !mod1) mk = SHIFT_CONTROL_PRESSED; else if (shift && !control && mod1) mk = SHIFT_MOD1_PRESSED; else if (!shift && control && mod1) mk = CONTROL_MOD1_PRESSED; else if (shift && control && mod1) mk = SHIFT_CONTROL_MOD1_PRESSED; else mk = NONE_PRESSED; return mk; } ButtonState ghid_button_state (GdkModifierType * state) { GdkModifierType mask; ButtonState bs; gboolean button1, button2, button3; GHidPort *out = &ghid_port; if (!state) gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area), NULL, NULL, &mask); else mask = *state; button1 = (mask & GDK_BUTTON1_MASK); button2 = (mask & GDK_BUTTON2_MASK); button3 = (mask & GDK_BUTTON3_MASK); if (button1) bs = BUTTON1_PRESSED; else if (button2) bs = BUTTON2_PRESSED; else if (button3) bs = BUTTON3_PRESSED; else bs = NO_BUTTON_PRESSED; return bs; } void ghid_draw_area_update (GHidPort * port, GdkRectangle * rect) { gdk_window_invalidate_rect (gtk_widget_get_window (port->drawing_area), rect, FALSE); } gchar * ghid_get_color_name (GdkColor * color) { gchar *name; if (!color) name = g_strdup ("#000000"); else name = g_strdup_printf ("#%2.2x%2.2x%2.2x", (color->red >> 8) & 0xff, (color->green >> 8) & 0xff, (color->blue >> 8) & 0xff); return name; } void ghid_map_color_string (char *color_string, GdkColor * color) { static GdkColormap *colormap = NULL; GHidPort *out = &ghid_port; if (!color || !out->top_window) return; if (colormap == NULL) colormap = gtk_widget_get_colormap (out->top_window); if (color->red || color->green || color->blue) gdk_colormap_free_colors (colormap, color, 1); gdk_color_parse (color_string, color); gdk_color_alloc (colormap, color); } gchar * ghid_entry_get_text (GtkWidget * entry) { gchar *s = ""; if (entry) s = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry)); while (*s == ' ' || *s == '\t') ++s; return s; } void ghid_check_button_connected (GtkWidget * box, GtkWidget ** button, gboolean active, gboolean pack_start, gboolean expand, gboolean fill, gint pad, void (*cb_func) (GtkToggleButton *, gpointer), gpointer data, gchar * string) { GtkWidget *b; if (!string) return; b = gtk_check_button_new_with_mnemonic (string); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b), active); if (box && pack_start) gtk_box_pack_start (GTK_BOX (box), b, expand, fill, pad); else if (box && !pack_start) gtk_box_pack_end (GTK_BOX (box), b, expand, fill, pad); if (cb_func) g_signal_connect (b, "clicked", G_CALLBACK (cb_func), data); if (button) *button = b; } void ghid_button_connected (GtkWidget * box, GtkWidget ** button, gboolean pack_start, gboolean expand, gboolean fill, gint pad, void (*cb_func) (gpointer), gpointer data, gchar * string) { GtkWidget *b; if (!string) return; b = gtk_button_new_with_mnemonic (string); if (box && pack_start) gtk_box_pack_start (GTK_BOX (box), b, expand, fill, pad); else if (box && !pack_start) gtk_box_pack_end (GTK_BOX (box), b, expand, fill, pad); if (cb_func) g_signal_connect (b, "clicked", G_CALLBACK (cb_func), data); if (button) *button = b; } void ghid_coord_entry (GtkWidget * box, GtkWidget ** coord_entry, Coord value, Coord low, Coord high, enum ce_step_size step_size, gint width, void (*cb_func) (GHidCoordEntry *, gpointer), gpointer data, gboolean right_align, gchar * string) { GtkWidget *hbox = NULL, *label, *entry_widget; GHidCoordEntry *entry; if (string && box) { hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 2); box = hbox; } entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size); if (coord_entry) *coord_entry = entry_widget; if (width > 0) gtk_widget_set_size_request (entry_widget, width, -1); entry = GHID_COORD_ENTRY (entry_widget); if (data == NULL) data = (gpointer) entry; if (cb_func) g_signal_connect (G_OBJECT (entry_widget), "value_changed", G_CALLBACK (cb_func), data); if (box) { if (right_align && string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2); } gtk_box_pack_start (GTK_BOX (box), entry_widget, FALSE, FALSE, 2); if (!right_align && string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2); } } } void ghid_spin_button (GtkWidget * box, GtkWidget ** spin_button, gfloat value, gfloat low, gfloat high, gfloat step0, gfloat step1, gint digits, gint width, void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, gchar * string) { GtkWidget *hbox = NULL, *label, *spin_but; GtkSpinButton *spin; GtkAdjustment *adj; if (string && box) { hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 2); box = hbox; } adj = (GtkAdjustment *) gtk_adjustment_new (value, low, high, step0, step1, 0.0); spin_but = gtk_spin_button_new (adj, 0.5, digits); if (spin_button) *spin_button = spin_but; if (width > 0) gtk_widget_set_size_request (spin_but, width, -1); spin = GTK_SPIN_BUTTON (spin_but); gtk_spin_button_set_numeric (spin, TRUE); if (data == NULL) data = (gpointer) spin; if (cb_func) g_signal_connect (G_OBJECT (spin_but), "value_changed", G_CALLBACK (cb_func), data); if (box) { if (right_align && string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2); } gtk_box_pack_start (GTK_BOX (box), spin_but, FALSE, FALSE, 2); if (!right_align && string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2); } } } void ghid_table_coord_entry (GtkWidget * table, gint row, gint column, GtkWidget ** coord_entry, Coord value, Coord low, Coord high, enum ce_step_size step_size, gint width, void (*cb_func) (GHidCoordEntry *, gpointer), gpointer data, gboolean right_align, gchar * string) { GtkWidget *label, *entry_widget; GHidCoordEntry *entry; if (!table) return; entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size); if (coord_entry) *coord_entry = entry_widget; if (width > 0) gtk_widget_set_size_request (entry_widget, width, -1); entry = GHID_COORD_ENTRY (entry_widget); if (data == NULL) data = (gpointer) entry; if (cb_func) g_signal_connect (G_OBJECT (entry), "value_changed", G_CALLBACK (cb_func), data); if (right_align) { gtk_table_attach_defaults (GTK_TABLE (table), entry_widget, column + 1, column + 2, row, row + 1); if (string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, column, column + 1, row, row + 1); } } else { gtk_table_attach_defaults (GTK_TABLE (table), entry_widget, column, column + 1, row, row + 1); if (string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, column + 1, column + 2, row, row + 1); } } } void ghid_table_spin_button (GtkWidget * table, gint row, gint column, GtkWidget ** spin_button, gfloat value, gfloat low, gfloat high, gfloat step0, gfloat step1, gint digits, gint width, void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align, gchar * string) { GtkWidget *label, *spin_but; GtkSpinButton *spin; GtkAdjustment *adj; if (!table) return; adj = (GtkAdjustment *) gtk_adjustment_new (value, low, high, step0, step1, 0.0); spin_but = gtk_spin_button_new (adj, 0.5, digits); if (spin_button) *spin_button = spin_but; if (width > 0) gtk_widget_set_size_request (spin_but, width, -1); spin = GTK_SPIN_BUTTON (spin_but); gtk_spin_button_set_numeric (spin, TRUE); if (data == NULL) data = (gpointer) spin; if (cb_func) g_signal_connect (G_OBJECT (spin_but), "value_changed", G_CALLBACK (cb_func), data); if (right_align) { gtk_table_attach_defaults (GTK_TABLE (table), spin_but, column + 1, column + 2, row, row + 1); if (string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, column, column + 1, row, row + 1); } } else { gtk_table_attach_defaults (GTK_TABLE (table), spin_but, column, column + 1, row, row + 1); if (string) { label = gtk_label_new (string); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_table_attach_defaults (GTK_TABLE (table), label, column + 1, column + 2, row, row + 1); } } } void ghid_range_control (GtkWidget * box, GtkWidget ** scale_res, gboolean horizontal, GtkPositionType pos, gboolean set_draw_value, gint digits, gboolean pack_start, gboolean expand, gboolean fill, guint pad, gfloat value, gfloat low, gfloat high, gfloat step0, gfloat step1, void (*cb_func) (), gpointer data) { GtkWidget *scale; GtkAdjustment *adj; adj = (GtkAdjustment *) gtk_adjustment_new (value, low, high, step0, step1, 0.0); if (horizontal) scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); else scale = gtk_vscale_new (GTK_ADJUSTMENT (adj)); gtk_scale_set_value_pos (GTK_SCALE (scale), pos); gtk_scale_set_draw_value (GTK_SCALE (scale), set_draw_value); gtk_scale_set_digits (GTK_SCALE (scale), digits); /* Increments don't make sense, use -1,1 because that does closest to | what I want: scroll down decrements slider value. */ gtk_range_set_increments (GTK_RANGE (scale), -1, 1); if (pack_start) gtk_box_pack_start (GTK_BOX (box), scale, expand, fill, pad); else gtk_box_pack_end (GTK_BOX (box), scale, expand, fill, pad); if (data == NULL) data = (gpointer) adj; if (cb_func) g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (cb_func), data); if (scale_res) *scale_res = scale; } GtkWidget * ghid_scrolled_vbox (GtkWidget * box, GtkWidget ** scr, GtkPolicyType h_policy, GtkPolicyType v_policy) { GtkWidget *scrolled, *vbox; scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), h_policy, v_policy); gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0); vbox = gtk_vbox_new (FALSE, 0); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled), vbox); if (scr) *scr = scrolled; return vbox; } /* frame_border_width - border around outside of frame. | vbox_pad - pad between widgets to be packed in returned vbox. | vbox_border_width - border between returned vbox and frame. */ GtkWidget * ghid_framed_vbox (GtkWidget * box, gchar * label, gint frame_border_width, gboolean frame_expand, gint vbox_pad, gint vbox_border_width) { GtkWidget *frame; GtkWidget *vbox; frame = gtk_frame_new (label); gtk_container_set_border_width (GTK_CONTAINER (frame), frame_border_width); gtk_box_pack_start (GTK_BOX (box), frame, frame_expand, frame_expand, 0); vbox = gtk_vbox_new (FALSE, vbox_pad); gtk_container_set_border_width (GTK_CONTAINER (vbox), vbox_border_width); gtk_container_add (GTK_CONTAINER (frame), vbox); return vbox; } GtkWidget * ghid_framed_vbox_end (GtkWidget * box, gchar * label, gint frame_border_width, gboolean frame_expand, gint vbox_pad, gint vbox_border_width) { GtkWidget *frame; GtkWidget *vbox; frame = gtk_frame_new (label); gtk_container_set_border_width (GTK_CONTAINER (frame), frame_border_width); gtk_box_pack_end (GTK_BOX (box), frame, frame_expand, frame_expand, 0); vbox = gtk_vbox_new (FALSE, vbox_pad); gtk_container_set_border_width (GTK_CONTAINER (vbox), vbox_border_width); gtk_container_add (GTK_CONTAINER (frame), vbox); return vbox; } GtkWidget * ghid_category_vbox (GtkWidget * box, const gchar * category_header, gint header_pad, gint box_pad, gboolean pack_start, gboolean bottom_pad) { GtkWidget *vbox, *vbox1, *hbox, *label; gchar *s; vbox = gtk_vbox_new (FALSE, 0); if (pack_start) gtk_box_pack_start (GTK_BOX (box), vbox, FALSE, FALSE, 0); else gtk_box_pack_end (GTK_BOX (box), vbox, FALSE, FALSE, 0); if (category_header) { label = gtk_label_new (NULL); s = g_strconcat ("", category_header, "", NULL); gtk_label_set_markup (GTK_LABEL (label), s); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, header_pad); g_free (s); } hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); label = gtk_label_new (" "); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); vbox1 = gtk_vbox_new (FALSE, box_pad); gtk_box_pack_start (GTK_BOX (hbox), vbox1, TRUE, TRUE, 0); if (bottom_pad) { label = gtk_label_new (""); gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); } return vbox1; } GtkTreeSelection * ghid_scrolled_selection (GtkTreeView * treeview, GtkWidget * box, GtkSelectionMode s_mode, GtkPolicyType h_policy, GtkPolicyType v_policy, void (*func_cb) (GtkTreeSelection *, gpointer), gpointer data) { GtkTreeSelection *selection; GtkWidget *scrolled; if (!box || !treeview) return NULL; scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (treeview)); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), h_policy, v_policy); selection = gtk_tree_view_get_selection (treeview); gtk_tree_selection_set_mode (selection, s_mode); if (func_cb) g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (func_cb), data); return selection; } GtkWidget * ghid_notebook_page (GtkWidget * tabs, const char *name, gint pad, gint border) { GtkWidget *label; GtkWidget *vbox; vbox = gtk_vbox_new (FALSE, pad); gtk_container_set_border_width (GTK_CONTAINER (vbox), border); label = gtk_label_new (name); gtk_notebook_append_page (GTK_NOTEBOOK (tabs), vbox, label); return vbox; } GtkWidget * ghid_framed_notebook_page (GtkWidget * tabs, char *name, gint border, gint frame_border, gint vbox_pad, gint vbox_border) { GtkWidget *vbox; vbox = ghid_notebook_page (tabs, name, 0, border); vbox = ghid_framed_vbox (vbox, NULL, frame_border, TRUE, vbox_pad, vbox_border); return vbox; } void ghid_dialog_report (gchar * title, gchar * message) { GtkWidget *top_win; GtkWidget *dialog; GtkWidget *content_area; GtkWidget *scrolled; GtkWidget *vbox, *vbox1; GtkWidget *label; gchar *s; gint nlines; GHidPort *out = &ghid_port; if (!message) return; top_win = out->top_window; dialog = gtk_dialog_new_with_buttons (title ? title : "PCB", GTK_WINDOW (top_win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_NONE, NULL); g_signal_connect_swapped (GTK_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), GTK_OBJECT (dialog)); gtk_window_set_wmclass (GTK_WINDOW (dialog), "PCB_Dialog", "PCB"); content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); vbox = gtk_vbox_new (FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); gtk_box_pack_start (GTK_BOX (content_area), vbox, FALSE, FALSE, 0); label = gtk_label_new (message); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); for (nlines = 0, s = message; *s; ++s) if (*s == '\n') ++nlines; if (nlines > 20) { vbox1 = ghid_scrolled_vbox (vbox, &scrolled, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_widget_set_size_request (scrolled, -1, 300); gtk_box_pack_start (GTK_BOX (vbox1), label, FALSE, FALSE, 0); } else gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); gtk_widget_show_all (dialog); } void ghid_label_set_markup (GtkWidget * label, const gchar * text) { if (label) gtk_label_set_markup (GTK_LABEL (label), text ? text : ""); } static void text_view_append (GtkWidget * view, gchar * s) { GtkTextIter iter; GtkTextBuffer *buffer; GtkTextMark *mark; buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); gtk_text_buffer_get_end_iter (buffer, &iter); /* gtk_text_iter_forward_to_end(&iter); */ if (strncmp (s, "", 3) == 0) gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, s + 3, -1, "bold", NULL); else if (strncmp (s, "", 3) == 0) gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, s + 3, -1, "italic", NULL); else if (strncmp (s, "", 3) == 0) gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, s + 3, -1, "heading", NULL); else if (strncmp (s, "", 3) == 0) gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, s + 3, -1, "center", NULL); else if (strncmp (s, "