/* * goto.c - a port of the Version 6 (V6) transfer command */ /*- * Copyright (c) 2004-2019 * Jeffrey Allen Neitzel . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JEFFREY ALLEN NEITZEL ``AS IS'', AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL JEFFREY ALLEN NEITZEL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @(#)$Id: goto.c,v 1.7 2019/03/17 15:28:49 jneitzel Exp $ */ /* * Derived from: V6 UNIX /usr/source/s1/goto.c */ /*- * Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * 4. Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "defs.h" #include "sh_err.h" #if 0 # if defined(CONFIG_BROKEN) # error "Ubuntu 16.(04|10)|17.04: Not supported: see https://etsh.nl/blog/ubuntu-16/" /* * Strictly speaking, goto works fine and sets the correct offset * on the standard input on Ubuntu 16.(04|10)|17.04, but the more * recent Ubuntu, 1[89].*, versions no longer have this problem. */ # endif #endif #if !(defined(CONFIG_LINUX) || defined(CONFIG_SUNOS)) static off_t offset; #endif static bool getlabel(/*@out@*/ char *, int, size_t); static int xgetc(void); /* * NAME * goto - transfer command * * SYNOPSIS * goto label [...] * * DESCRIPTION * See the goto(1) manual page for full details. */ int main(int argc, char **argv) { size_t siz; char label[LABELMAX]; setmyerrexit(&ut_errexit); setmyname(argv[0]); setmypid(getpid()); if (argc < 2 || *argv[1] == EOS || isatty(FD0) != 0) sh_err(FC_ERR, FMT2S, getmyname(), ERR_GENERIC); if ((siz = strlen(argv[1]) + 1) > sizeof(label)) sh_err(FC_ERR, FMT3S, getmyname(), argv[1], ERR_LABTOOLONG); if (lseek(FD0, (off_t)0, SEEK_SET) == -1) sh_err(FC_ERR, FMT2S, getmyname(), ERR_SEEK); while (getlabel(label, U_CHAR(*argv[1] & 0377), siz)) if (strcmp(label, argv[1]) == 0) { #if !(defined(CONFIG_LINUX) || defined(CONFIG_SUNOS)) (void)lseek(FD0, offset, SEEK_SET); #endif return SH_TRUE; } fd_print(FD2, FMT3S, getmyname(), argv[1], ERR_LABNOTFOUND); return SH_FALSE; } /* * Search for the first occurrence of a possible label with both * the same first character (fc) and the same length (siz - 1) * as argv[1], and copy this possible label to buf. * Return true (1) if possible label found. * Return false (0) at end-of-file. */ static bool getlabel(char *buf, int fc, size_t siz) { int c; char *b; while ((c = xgetc()) != EOF) { /* `:' may be preceded by blanks. */ while (c == SPC || c == TAB) c = xgetc(); if (c != COLON) { while (c != EOL && c != EOF) c = xgetc(); continue; } /* Prepare for possible label. */ while ((c = xgetc()) == SPC || c == TAB) ; /* nothing */ if (c != fc) /* not label */ continue; /* * Try to copy possible label (first word only) * to buf, ignoring it if it becomes too long. */ b = buf; do { if (c == EOL || c == SPC || c == TAB || c == EOF) { *b = EOS; break; } *b = c; c = xgetc(); } while (++b < &buf[siz]); /* Ignore any remaining characters on labelled line. */ while (c != EOL && c != EOF) c = xgetc(); if (c == EOF) break; if ((size_t)(b - buf) != siz - 1) /* not label */ continue; return true; } *buf = EOS; return false; } /* * If not at end-of-file, return the next character from the standard * input as an unsigned char converted to an int while incrementing * the global offset. Otherwise, return EOF at end-of-file. */ static int xgetc(void) { #if !(defined(CONFIG_LINUX) || defined(CONFIG_SUNOS)) int nc; offset++; nc = getchar(); if (nc != EOF) { nc = U_CHAR(nc & 0377); return nc; } return EOF; #else u_char nc; if (read(FD0, &nc, (size_t)1) == 1) return nc; return EOF; #endif }