<<

CS246 : script parameters C:doing with structs April 21 : printer.c Lab 4/19 void parray2(void * base, size_t nmemb, size_t size, char* fmt) { for (int i = 0; i < nmemb; i++) { • char c = *((char *)base); // problematic line suggest, and printf(fmt, c); provide an base += size; implementation } for, a way to printf(“\n"); the array }

printer program int main(int argc, char const *argv[]) { truly generic srand((NULL)); • Hint — function char aa[100]; for (int i = 0; i < 100; i++) pointers!!! aa[i] = 'a' + (rand() % 26); parray2(aa, 100, sizeof(char), "%c"); }

2 char * pprinter3(void * item) { char *citem = (char *)item; char *rtn = malloc(6 * sizeof(char)); A v3 sprintf(rtn, "<%c>", *citem); return rtn; } • Problems ?? void parray3(void * base, size_t nmemb, size_t size, char *(*f)(void *)) { for (int i = 0; i < nmemb; i++) { printf("%s ", f(base)); base += size; } printf("\n"); } int main(int argc, char const *argv[]) { srand(time(NULL)); char aa[100]; for (int i = 0; i < 100; i++) aa[i] = 'a' + (rand() % 26);

parray3(aa, 10, sizeof(char), pprinter3); 3 } void parray3(void * base, size_t nmemb, size_t size, char*(*f)(void*)) { A v3a, v4 for (int i = 0; i < nmemb; i++) { char *tmp = f(base); printf("%s ", tmp); base += size; • free the memory!! free(tmp); } printf("\n"); • Or statically declare } void pprinter4(void * item, char* printInto) { char array and pass char *citem = (char *)item; it sprintf(printInto, "[%c]", *citem); } • advantages/ void parray4(void * base, size_t nmemb, size_t size, disadvantages?? void(*f)(void*,char*)) { char aa[100]; for (int i = 0; i < nmemb; i++) { f(base, aa); printf("%s ", aa); base += size; } printf("\n"); 4 } Shell Scripts — command line params

• recall $1 … $9 are arguments 1..9 on command line • $0 is the name of the script • just like main in C • If you have more than 9, then ${12}, • can do this on all … ${4} == $4 • BUT this does not • FOU=4 ${$FOU} • So … how to loop through command line args????

5 Working with lots of command line args

• When would this come up?? • Recall script from 2 weeks ago for totaling up size of executables with an extension • This was limited as it required that the files have a common extension. • Better would be just to take a set of files as command line args • for instance “p.sh *.exe L*” • This would pass to the script p.sh all files that either begin with L or end with .exe • There could be 100s

6 shell scripts with lots of command line params

• This approach works #!/bin/bash • kind of PP="$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10}“ • When there are for aa in $PP than 10 CLPs they do get put into the $aa string PP as blanks so done the iteration only goes for existing values • Problem: more than 10

7 Handling larges number of CLPs

• $* and $@ #!/bin/bash • both “ into the list of for aa in $* positional parameters do echo "A $aa" done • $# for aa in $@ • the number of positional do parameters echo "B $aa" done • GACKK — this is feeling like Perl

8 Loop over all Command line params file: summer.sh command line params

FILES=` *.${1}` TOT=0 TOT=0 for FILE in $@ for FILE in $FILES do do if [[ -x $FILE && -f $FILE ]] Added condition that DET=`ls -l $FILE` item must be a file then CNT=0 and be executable DET=`ls -l $FILE` for DETP in $DET CNT=0 do for DETP in $DET #echo "$CNT $DETP" do if [ $CNT -eq 4 ] if [ $CNT -eq 4 ] then then TOT=$(( $TOT + $DETP )) TOT=$(( $TOT + $DETP )) #echo $DETP echo $FILE $DETP fi fi ((CNT++)) ((CNT++)) done done done fi echo $TOT done 9 echo $TOT HAIRBALL!!! Shell Script Arrays actually the number of items in array

#!/bin/bash AA=(ONE TWO THREE) for ((i=0; i<${#AA[@]}; i++)) Create an array do echo $i ${AA[$i]} $AA[$i] done

This will print the Correct way to get value of $AA followed array value by value of $i inside []

10 Putting this together

#!/bin/bash TOT=0 for FILE in $@ do String result of command is if [[ -x $FILE && -f $FILE ]] broken apart then put into then array! ADET=( `ls -l $FILE` ) TOT=$(( $TOT + ${ADET[4]} )) echo $FILE ${ADET[4]} ((CNT++)) fi Using array index avoids done awkward and strange loop. echo $TOT

11 Making structs more Object like

• transparent inheritance • functions • private vars

12 #include typedef struct { int x; Transparent int y; } aa; inheritance Anonymous union typedef struct { contains both • anonymous structures/ union { anonymous struct and aa; unions named struct. aa aaa; • allow referring to items in }; You can use either!! int z; included structures without } bb; annoying extra dots ( I always forget) int main(int argc, char const *argv[]) { • MUST COMPILE USING bb b; Using both! gcc -fms-extensions b.aaa.x = 10; typedef struct { b.y = 40; int x; b.z = 20; int y; printf("%d %d %d\n", b.z, b.aaa.x, b.y); } aa; return 0; typedef struct { } aa; Simple use int z; 13 } bb; file: sp1.h function pointers typedef struct qq { int a; int b; in structs void (*printer)(struct qq *); } qq; • Why: qq *makeQQ(int a, int b); • stylistic choice • can fewer naming collisions

• the public name is inside file: sp1.c struct so that name does not conflict with anything Name only #include exists within #include "sp1.h" • In feels “Object-y” this file #include • Why not: static void printer(qq * p) { printf("QQ: %d %d\n", p->a, p->b); • space for the pointer } • Cannot do this for qq* makeQQ(int a, int b) { constructors & destructors qq *q = malloc(1 * sizeof(qq)); q->a = a; q->b = b; q->printer = printer; 14 } function pointers #include in structs #include "sp1.h"

• static keyword on void printer(qq* q3) { printer function on printf("333 a:%d b:%d\n", q3->a, q3->b); previous page means } that printer here does not conflict. int main(int argc, char const *argv[]) { • ideally all “private” qq *q = makeQQ(4, 5); functions are static q->printer(q); printer(q); • function is only return 0; “public” through } pointer within the struct.

15 typedef struct { int private1; Private Vars } privNAM; int getYear(privNAM* pn) { • DO NOT EXIST!! return pn->private1; } • But void setYear(privNAM* pn, int yr) { • Privacy through pn->private1 = yr; naming } privNAM* makePrivNAM() { • Idea: name return malloc(1 * sizeof(privNAM)); variable to indicate } they are private int main(int argc, char const *argv[]) { • provide well- privNAM *pn = makePrivNAM(); named get/set setYear(pn, 1961); • People can still printf("%d\n", getYear(pn)); directly read but it is return 0; they should not. }

16 typedef struct { need to void* private1; handle if } privOI; not int getYear(privOI* pn) { allocated Private Variables int *ip = pn->private1; return *ip; } • Privacy through obscure void setYear(privOI* pn, int yr) { indirection Only if (pn->private1 == NULL) { • Idea, store private vars allocate pn->private1 = malloc(1 * sizeof(int)); space } when behind void * pointers int *ip = pn->private1; needed • again, well named get/ *ip = yr; set } privOI* makePrivOI() { • People can change the privOI* poi = malloc(1 * sizeof(privOI)); pointer, but clear they } should not. int main(int argc, char const *argv[]) { privOI *pn = makePrivOI(); • Unreadable!! except setYear(pn, 1961); through determined idiocy. printf("%d\n", getYear(pn)); return 0; } 17 Roll your own typedef struct { garbage collector char *string; } stringRC; • Suppose a struct that contains string • its own private copy typedef struct { stringRC* string; • Also a substring struct int strt; • a pointer to the string struct int len; • starting point for substring } substringRC;

• length of substring void printSubstr(substringRC* sstr) { • Problem: for (int i = 0; i < sstr->len; i++) • should not free the string struct until printf("%c", sstr->string->string[sstr->strt + i]); all of the substrings using it are free! printf("\n"); } HOW?? • void printString(stringRC *str) { printf("%s\n", str->string); • Create your own mini garbage collector!! } 18 Implement void freeStringRC(stringRC* str) { if (str->refCount==0) { printf(“NO Refs -- freeing\n"); reference counting free(str->string); free(str); typedef struct { Free main string iff there are no } else { char *string; references to it printf("Not freeing -- still has refs [%d]\n", str->refCount); int refCount; Otherwise mark it as ready to str->mainFreed = 1; int mainFreed; be freed } } stringRC; } void freeSubstringRC(substringRC* src) { stringRC* makeStringRC(char * src) { stringRC *tmp = src->string; // stuff not shown free(src); rc->refCount = 0; tmp->refCount--; rc->mainFreed = 0; if (tmp->refCount==0 && tmp->mainFreed) { return rc; freeStringRC(tmp); } } } substringRC* makeSubstringRC(stringRC* str, int call free on main string iff the st, int len) { only reason main string exists is // stuff not shown because of references str->refCount++; return src; 19 } int main(int argc, char const *argv[]) int main(int argc, char const *argv[]) { { stringRC *rc = makeStringRC("now stringRC *rc = makeStringRC("now is the time of all good people to come is the time of all good people to come to the aid of their country"); to the aid of their country"); substringRC *src1 = substringRC *src1 = makeSubstringRC(rc, 0, 5); makeSubstringRC(rc, 0, 5); printSubstr(src1); printString(rc); freeSubstringRC(src1); freeStringRC(rc); printString(rc); printSubstr(src1); freeStringRC(rc); freeSubstringRC(src1); return 0; return 0; } }

20 Lab

a shell script that sums the size of all writeable files in this directory and all directories immediately below this directory. • The shell script should not do any directory traversal or listing on its own. Rather all of the file names should be given as command line parameters • Send me a copy of your script and the unix command line through which this script would be invoked to do the above task.

• OR • today is earth day. Send me a picture of you outside, today. include something in the picture to show that the picture was taken today. • OR • if you are on campus, go build/decorate a birdhouse. Send me a picture of your birdhouse

21