Rev 7076 | Rev 8100 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 7076 | Rev 7079 | ||
---|---|---|---|
Line 13... | Line 13... | ||
13 | * You should have received a copy of the GNU General Public License |
13 | * You should have received a copy of the GNU General Public License |
14 | * along with this program; if not, write to the Free Software |
14 | * along with this program; if not, write to the Free Software |
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
15 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
16 | */ |
16 | */ |
17 | 17 | ||
18 |
|
18 | /* Computes class connection count (unit: student-minutes) */ |
19 | 19 | ||
20 | #include "../wimsdef.h" |
20 | #include "../wimsdef.h" |
21 | #include "../includes.h" |
21 | #include "../includes.h" |
22 | #include "../Lib/basicstr.c" |
22 | #include "../Lib/basicstr.c" |
23 | 23 | ||
24 |
|
24 | /* The maximal number of sessions within one day */ |
25 | #define MAX_SESSIONS (128*1024) |
25 | #define MAX_SESSIONS (128*1024) |
26 |
|
26 | /* The maximal number of classes within one day */ |
27 | #define MAX_CLASSES 8192 |
27 | #define MAX_CLASSES 8192 |
28 |
|
28 | /* At least these minutes will be counted for each session */ |
29 | #define MIN_CONNECT 2 |
29 | #define MIN_CONNECT 2 |
30 |
|
30 | /* Add this number of minutes to each session */ |
31 | #define MIN_ADD 1 |
31 | #define MIN_ADD 1 |
32 |
|
32 | /* Accounting discontinues after this number of idle minutes */ |
33 | #define MAX_LAPSE 15 |
33 | #define MAX_LAPSE 15 |
34 | 34 | ||
35 | struct { |
35 | struct { |
36 | char s[4], u[32]; |
36 | char s[4], u[32]; |
37 | int cl, start, end, cnt; |
37 | int cl, start, end, cnt; |
Line 48... | Line 48... | ||
48 | void *xmalloc(size_t n) |
48 | void *xmalloc(size_t n) |
49 | { |
49 | { |
50 | void *p; |
50 | void *p; |
51 | p=malloc(n); |
51 | p=malloc(n); |
52 | if(p==NULL) { |
52 | if(p==NULL) { |
53 |
|
53 | fprintf(stderr,"Malloc failure."); exit(1); |
54 | } |
54 | } |
55 | return p; |
55 | return p; |
56 | } |
56 | } |
57 | 57 | ||
58 |
|
58 | /* Points to the end of the word */ |
59 | char *find_word_end(char *p) |
59 | char *find_word_end(char *p) |
60 | { |
60 | { |
61 | int i; |
61 | int i; |
62 | for(i=0;!isspace(*p) && *p!=0 && i<MAX_LINELEN; p++,i++); |
62 | for(i=0;!isspace(*p) && *p!=0 && i<MAX_LINELEN; p++,i++); |
63 | return p; |
63 | return p; |
64 | } |
64 | } |
65 | 65 | ||
66 |
|
66 | /* Strips leading spaces */ |
67 | char *find_word_start(char *p) |
67 | char *find_word_start(char *p) |
68 | { |
68 | { |
69 | int i; |
69 | int i; |
70 | for(i=0; isspace(*p) && i<MAX_LINELEN; p++,i++); |
70 | for(i=0; isspace(*p) && i<MAX_LINELEN; p++,i++); |
71 | return p; |
71 | return p; |
72 | } |
72 | } |
73 | 73 | ||
74 |
|
74 | /* Read/write to a file with variable parms to print filename */ |
75 | void accessfile(char *content, char *type, char *s,...) |
75 | void accessfile(char *content, char *type, char *s,...) |
76 | { |
76 | { |
77 | va_list vp; |
77 | va_list vp; |
78 | char buf[MAX_LINELEN+1]; |
78 | char buf[MAX_LINELEN+1]; |
79 | FILE *f; |
79 | FILE *f; |
Line 81... | Line 81... | ||
81 | 81 | ||
82 | va_start(vp,s); |
82 | va_start(vp,s); |
83 | vsnprintf(buf,sizeof(buf),s,vp); |
83 | vsnprintf(buf,sizeof(buf),s,vp); |
84 | va_end(vp); |
84 | va_end(vp); |
85 | f=fopen(buf,type); if(f==NULL) { |
85 | f=fopen(buf,type); if(f==NULL) { |
86 |
|
86 | if(*type=='r') content[0]=0; return; |
87 | } |
87 | } |
88 | switch(*type) { |
88 | switch(*type) { |
89 |
|
89 | case 'a': |
90 |
|
90 | case 'w': { |
91 |
|
91 | l=strlen(content); fwrite(content,1,l,f); break; |
92 |
|
92 | } |
93 |
|
93 | case 'r': { |
94 |
|
94 | l=fread(content,1,MAX_LINELEN-1,f); |
95 |
|
95 | if(l>0 && l<MAX_LINELEN) content[l]=0; |
96 |
|
96 | else content[0]=0; |
97 |
|
97 | break; |
98 |
|
98 | } |
99 |
|
99 | default: { |
100 |
|
100 | content[0]=0; break; |
101 |
|
101 | } |
102 | } |
102 | } |
103 | fclose(f); |
103 | fclose(f); |
104 | } |
104 | } |
105 | 105 | ||
106 |
|
106 | /* returns -1 if error */ |
107 | long int filelength(char *fn,...) |
107 | long int filelength(char *fn,...) |
108 | { |
108 | { |
109 | char buf[4096]; |
109 | char buf[4096]; |
110 | va_list vp; |
110 | va_list vp; |
111 | struct stat st; |
111 | struct stat st; |
112 | int l; |
112 | int l; |
113 | 113 | ||
114 | va_start(vp,fn); |
114 | va_start(vp,fn); |
115 | vsnprintf(buf,sizeof(buf),fn,vp); va_end(vp); |
115 | vsnprintf(buf,sizeof(buf),fn,vp); va_end(vp); |
116 | l=stat(buf,&st); if(l) return -1; |
116 | l=stat(buf,&st); if(l) return -1; |
117 | return st.st_size; |
117 | return st.st_size; |
118 | } |
118 | } |
119 | 119 | ||
120 |
|
120 | /* recursively generate a directory structure */ |
121 | void mkdirs(char *s) |
121 | void mkdirs(char *s) |
122 | { |
122 | { |
123 | struct stat st; |
123 | struct stat st; |
124 | char *buf; |
124 | char *buf; |
125 | if(stat(s,&st)==-1) { |
125 | if(stat(s,&st)==-1) { |
126 |
|
126 | if(strrchr(s,'/')!=NULL) { |
127 |
|
127 | buf=xmalloc(strlen(s)+1); |
128 |
|
128 | ovlstrcpy(buf,s); *strrchr(buf,'/')=0; |
129 |
|
129 | mkdirs(buf); free(buf); |
130 |
|
130 | } |
131 |
|
131 | mkdir(s,-1); |
132 | } |
132 | } |
133 | } |
133 | } |
134 | 134 | ||
135 | void oneline(char *p) |
135 | void oneline(char *p) |
136 | { |
136 | { |
Line 141... | Line 141... | ||
141 | t=atoi(tbuf)*60+atoi(tbuf+3); |
141 | t=atoi(tbuf)*60+atoi(tbuf+3); |
142 | memmove(sbuf,p+18,4); sbuf[4]=0; |
142 | memmove(sbuf,p+18,4); sbuf[4]=0; |
143 | p1=strchr(p,','); if(p1==NULL) return; |
143 | p1=strchr(p,','); if(p1==NULL) return; |
144 | if(!isdigit(*(p1+1))) return; |
144 | if(!isdigit(*(p1+1))) return; |
145 | snprintf(cbuf,sizeof(cbuf),"%s",p1+1); |
145 | snprintf(cbuf,sizeof(cbuf),"%s",p1+1); |
146 | for(p2=cbuf;isdigit(*p2); p2++); |
146 | for(p2=cbuf;isdigit(*p2); p2++){}; |
147 | *p2=0; cl=atoi(cbuf); |
147 | *p2=0; cl=atoi(cbuf); |
148 | *p1=0; for(p1--;p1>p && !isspace(*(p1-1)); p1--); |
148 | *p1=0; for(p1--;p1>p && !isspace(*(p1-1)); p1--); |
149 | snprintf(ubuf,sizeof(ubuf),"%s",p1); |
149 | snprintf(ubuf,sizeof(ubuf),"%s",p1); |
150 | for(i=0;i<sescnt;i++) { |
150 | for(i=0;i<sescnt;i++) { |
151 |
|
151 | if(cl==ses[i].cl && memcmp(sbuf,ses[i].s,4)==0 && |
152 |
|
152 | ses[i].end>=t-MAX_LAPSE) { |
153 |
|
153 | ses[i].end=t; return; |
154 |
|
154 | } |
155 | } |
155 | } |
156 | if(sescnt>=MAX_SESSIONS) return; |
156 | if(sescnt>=MAX_SESSIONS) return; |
157 | memmove(ses[sescnt].s,sbuf,4); ses[sescnt].cl=cl; |
157 | memmove(ses[sescnt].s,sbuf,4); ses[sescnt].cl=cl; |
158 | ses[sescnt].start=ses[sescnt].end=t; |
158 | ses[sescnt].start=ses[sescnt].end=t; |
159 | snprintf(ses[sescnt].u,sizeof(ses[sescnt].u),"%s",ubuf); |
159 | snprintf(ses[sescnt].u,sizeof(ses[sescnt].u),"%s",ubuf); |
Line 167... | Line 167... | ||
167 | char *fbuf, *p1, *p2, *p3; |
167 | char *fbuf, *p1, *p2, *p3; |
168 | l=filelength(fname); if(l<=0) return; |
168 | l=filelength(fname); if(l<=0) return; |
169 | f=fopen(fname,"r"); if(f==NULL) return; |
169 | f=fopen(fname,"r"); if(f==NULL) return; |
170 | fbuf=xmalloc(l+16); (void)fread(fbuf,1,l,f); fclose(f); fbuf[l]=0; |
170 | fbuf=xmalloc(l+16); (void)fread(fbuf,1,l,f); fclose(f); fbuf[l]=0; |
171 | for(p1=fbuf; *p1; p1=p2) { |
171 | for(p1=fbuf; *p1; p1=p2) { |
172 |
|
172 | p2=strchr(p1,'\n'); if(p2==NULL) p2=p1+strlen(p1); else *p2++=0; |
173 |
|
173 | p3=strchr(p1,','); if(p3==NULL) continue; |
174 |
|
174 | if(strncmp(p1,datestr,8)!=0) continue; |
175 |
|
175 | oneline(p1); |
176 | } |
176 | } |
177 | } |
177 | } |
178 | 178 | ||
179 | void classaccount(void) |
179 | void classaccount(void) |
180 | { |
180 | { |
181 | int i,j; |
181 | int i,j; |
182 | clscnt=0; |
182 | clscnt=0; |
183 | for(i=0;i<sescnt;i++) { |
183 | for(i=0;i<sescnt;i++) { |
184 |
|
184 | ses[i].cnt=ses[i].end-ses[i].start+MIN_ADD; |
185 |
|
185 | if(ses[i].cnt<MIN_CONNECT) ses[i].cnt=MIN_CONNECT; |
186 |
|
186 | for(j=0;j<clscnt && ses[i].cl!=cls[j].cl;j++); |
187 |
|
187 | if(j<clscnt) cls[j].cnt+=ses[i].cnt; |
188 |
|
188 | else if(clscnt<MAX_CLASSES) { |
189 |
|
189 | cls[clscnt].cl=ses[i].cl; |
190 |
|
190 | cls[clscnt].cnt=ses[i].cnt; |
191 |
|
191 | clscnt++; |
192 |
|
192 | } |
193 | } |
193 | } |
194 | } |
194 | } |
195 | 195 | ||
196 | int clscmp(const void *c1, const void *c2) |
196 | int clscmp(const void *c1, const void *c2) |
197 | { |
197 | { |
Line 204... | Line 204... | ||
204 | { |
204 | { |
205 | char *p, buf[1024], dbuf[1024]; |
205 | char *p, buf[1024], dbuf[1024]; |
206 | int i,t; |
206 | int i,t; |
207 | p=getenv("ccsum_outdir"); if(p==NULL || *p==0) return; |
207 | p=getenv("ccsum_outdir"); if(p==NULL || *p==0) return; |
208 | for(i=0;i<sescnt;i++) { |
208 | for(i=0;i<sescnt;i++) { |
209 |
|
209 | snprintf(dbuf,sizeof(dbuf),"%s/%d",p,ses[i].cl); |
210 |
|
210 | mkdirs(dbuf); |
211 |
|
211 | snprintf(buf,sizeof(buf),"%s.%02d:%02d %d\n", |
212 |
|
212 | datestr,ses[i].start/60,ses[i].start%60,ses[i].cnt); |
213 |
|
213 | accessfile(buf,"a","%s/%s",dbuf,ses[i].u); |
214 | } |
214 | } |
215 | snprintf(dbuf,sizeof(dbuf),"%s/bydate/%.4s",p,datestr); |
215 | snprintf(dbuf,sizeof(dbuf),"%s/bydate/%.4s",p,datestr); |
216 | mkdirs(dbuf); |
216 | mkdirs(dbuf); |
217 | snprintf(dbuf+strlen(dbuf),sizeof(dbuf)-strlen(dbuf),"/%.2s",datestr+4); |
217 | snprintf(dbuf+strlen(dbuf),sizeof(dbuf)-strlen(dbuf),"/%.2s",datestr+4); |
218 | t=0; |
218 | t=0; |
219 | qsort(cls,clscnt,sizeof(cls[0]),clscmp); |
219 | qsort(cls,clscnt,sizeof(cls[0]),clscmp); |
220 | for(i=0;i<clscnt;i++) { |
220 | for(i=0;i<clscnt;i++) { |
221 |
|
221 | snprintf(buf,sizeof(buf),"%s %d\n",datestr,cls[i].cnt); |
222 |
|
222 | accessfile(buf,"a","%s/%d/.total",p,cls[i].cl); |
223 |
|
223 | snprintf(buf,sizeof(buf),"%s %d %d\n",datestr+4,cls[i].cl,cls[i].cnt); |
224 |
|
224 | accessfile(buf,"a","%s",dbuf); |
225 |
|
225 | t+=cls[i].cnt; |
226 | } |
226 | } |
227 | snprintf(buf,sizeof(buf),"%s %d %d\n",datestr,t,(t+30)/60); |
227 | snprintf(buf,sizeof(buf),"%s %d %d\n",datestr,t,(t+30)/60); |
228 | accessfile(buf,"a","%s/done",p); |
228 | accessfile(buf,"a","%s/done",p); |
229 | } |
229 | } |
230 | 230 |