rf@wu1.UUCP (11/20/84)
Does anyone know of any system on which the acat() routine in the program test.c (attached) does not work? Acat is part of a string management package -- an allocating concatenate routine. It takes up to 10 strings, allocates storage for their concatenation and concatenates them. The output of test.c is given. Test.c will end with the error message "test: More than 10 strings in acat()". Randolph Fritz UUCPnet: {ihnp4,decvax}!philabs!wu1!rf "Rust and moth are the only true Critics; . . ." -- "The True Critics", Paul Edwin Zimmer ----------------- output of test.c 1 122 122333 1223334444 122333444455555 122333444455555666666 1223334444555556666667777777 122333444455555666666777777788888888 122333444455555666666777777788888888999999999 ----------------- test.c #include <stdio.h> typedef int VOID; typedef unsigned int COUNT; typedef char TEXT; typedef int BOOL; #define EOS '\0' /* End-of-string */ #define NO ((BOOL) 0) /* Logic false */ #define YES ((BOOL) 1) /* Logic true */ TEXT *acat(), *stralloc(); main () { fprintf (stdout, "%s\n", acat("", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333","4444", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333","4444","55555", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333","4444","55555","666666", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333","4444","55555","666666", "7777777", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333","4444","55555","666666", "7777777","88888888", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333","4444","55555","666666", "7777777","88888888","999999999", NULL)); fflush (stdout); fprintf (stdout, "%s\n", acat("","1","22","333","4444","55555","666666", "7777777","88888888","999999999","10101010101010101010", NULL)); fflush (stdout); } /* acat - allocating string concatenate (for up to 10 strings) This (believed to be) portable routine will concatenate up to 10 strings. Acat() is invoked by: newstring = acat (string1, string2 , . . . stringn, NULL); Acat is by no means elegant -- it even contains (horrors!) a goto -- but it provides an amazingly useful function. */ TEXT * acat (s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10) TEXT *s0, *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9, *s10; { TEXT *instr[11]; COUNT newlen, nstr, i; TEXT *news, *np, *op; nstr = 0; if (s0!=NULL) instr[nstr++] = s0; else goto got_em; if (s1!=NULL) instr[nstr++] = s1; else goto got_em; if (s2!=NULL) instr[nstr++] = s2; else goto got_em; if (s3!=NULL) instr[nstr++] = s3; else goto got_em; if (s4!=NULL) instr[nstr++] = s4; else goto got_em; if (s5!=NULL) instr[nstr++] = s5; else goto got_em; if (s6!=NULL) instr[nstr++] = s6; else goto got_em; if (s7!=NULL) instr[nstr++] = s7; else goto got_em; if (s8!=NULL) instr[nstr++] = s8; else goto got_em; if (s9!=NULL) instr[nstr++] = s9; else goto got_em; if (s10!=NULL) bugout ("More than 10 strings in acat()\n"); got_em: instr[nstr] = NULL; newlen = 0; for (i=0; i<nstr; i++) newlen += strlen(instr[i]); newlen += 1; /* Allow space for an EOS */ news = stralloc(newlen); np = news; for (i=0; i<nstr; i++) { op = instr[i]; while ( (*np++ = *op++)!=EOS ) ; np--; } return news; } TEXT *progname = "test"; /* bugout - what to do when totally stuck or confused Writes s to standard error, prefixed by the program name, then exits with the "bomb" return code, 3. */ VOID bugout (s) TEXT *s; { extern TEXT *progname; fprintf (stderr, "%s: %s", progname, s); exit (3); } /* stralloc - string allocate Allocate n characters using calloc. Bug out if there's no storage to get. This routine really ought not use calloc. */ TEXT * stralloc(n) COUNT n; { TEXT *news; news = (TEXT *) calloc(n,sizeof(TEXT)); if (news==NULL) bugout ("Out of main memory in stralloc()\n"); return news; }
henry@utzoo.UUCP (Henry Spencer) (11/22/84)
> Does anyone know of any system on which the acat() routine in > the program test.c (attached) does not work? Dozens of them. Acat is taking variable-length argument lists, which is the kiss of death for portability. Declaring lots of parameters and then using them in order is highly machine-dependent; it makes major assumptions about how the argument list is laid out in memory. Using <varargs.h> would be a lot better, but even that is not perfect. There exist machines on which <varargs.h> is unimplementable. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
john@physiol.OZ (John Mackin) (11/30/84)
In article <4669@utzoo.UUCP>, henry@utzoo.UUCP writes: > There exist machines on which <varargs.h> is unimplementable. I'd be very interested in some specific examples. Machines already running UNIX, please, or likely to run it: not antiques. John Mackin, Physiology Department, University of Sydney, Sydney, Australia ...!decvax!mulga!physiol.su.oz!john
henry@utzoo.UUCP (Henry Spencer) (12/02/84)
> > There exist machines on which <varargs.h> is unimplementable. > > I'd be very interested in some specific examples. Machines > already running UNIX, please, or likely to run it: not > antiques. The PERQ, on which the parameter list of a function must have a constant length, the same length for all calls. I studied compiling C for the PERQ as part of my M.Sc. thesis, and friends of mine actually carried this to a full implementation for a commercial UNIX port. It was a memorable bad experience for them, by the way, and the company would rather forget it ever did that port (which is why I'm not identifying either the people or the company). <varargs.h> is also rather hard on machines like the Z8000, where the most common compilers pass parameters in registers. It's not utterly impossible on the Z8000, but the principle easily generalizes to almost arbitrary difficulty. (E.g., what if different datatypes go in different register sets?) -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
jeff@gatech.UUCP (Jeff Lee) (12/06/84)
> In article <4669@utzoo.UUCP>, henry@utzoo.UUCP writes: > > > There exist machines on which <varargs.h> is unimplementable. > > I'd be very interested in some specific examples. Machines > already running UNIX, please, or likely to run it: not > antiques. > > John Mackin, Physiology Department, University of Sydney, Sydney, Australia > ...!decvax!mulga!physiol.su.oz!john In a C compiler that was implemented on our Primes, the only way to provide it was to have the <varargs.h> package declare as many arguments as (hopefully) would ever be used and hope that was enough. I think this is a hack. It works (barely) but if any other machines have any more restrictions then it would be impossible. The problem is that procedure entry handles the stack allocation for you (thanks a lot). It has the number of parameters is kept in the entry control block and it will not transfer any more arguments than are accounted for in the control block. This is actually more serious than it may seem, because the parameter pointers are kept in procedure space following the procedure call which means that the return program counter (not accessible, really) is not bumped past the arguments and you end up executing data pointers. Ok, so we can allocate a possible 50 arguments (we actually use 10) but then you run into the problem that it takes 2.4 microseconds per actual argument EXPECTED (on a P400, past the initial 12.6 microseconds for the PCL). This makes those calls seem REAL LONG. The result is that <varargs.h> is supplied but you pay for it and it isn't a general purpose facility. -- Jeff Lee CSNet: Jeff @ GATech ARPA: Jeff.GATech @ CSNet-Relay uucp: ...!{akgua,allegra,rlgvax,sb1,unmvax,ulysses,ut-sally}!gatech!jeff