#include #define NUM_WIDTH 0 #define NUM_PRECISION 1 #define NUM_INDENT 2 #define NUM_NOTHING -1 #define ALIGN_LEFT 0 #define ALIGN_RIGHT 1 #define ALIGN_CENTRE 2 #define ALIGN_JUSTIFIED 3 #define TYPE_NORMAL 0 #define TYPE_COLUMN 1 #define TYPE_TABLE 2 inherit "/kernel/lib/strings"; string *result; string format; mixed *args; int posn; int output_line_index; mixed *numbers; int alignment; int type; int err; string pad_char; private int error(int flag, string error_type) { if (flag) { debug_message("sprintf error: "+error_type); err=1; } return flag; } string repeat_string(string str, int length) { /* Returns a string of the given length consisting of repetitions of str */ string result; int current_length; if (length>0) { result=str; current_length=strlen(result); while(current_length<=length) { result+=result; current_length+=current_length; } return result[..length-1]; } else { return ""; } } string make_spaces(int num) { return repeat_string(" ", num); } private string justify_text(string s, int width) { string *bits; int extra; int size; int x, y, r; x=strlen(s)-1; while (s!=" " && s[x]==' ') { s=s[..x-1]; x--; } extra=width-strlen(s); if (extra<=0) { return s; } bits=explode(s, " "); size=sizeof(bits)-1; if (size<1) { return s; } r=extra; x=y=0; while(y=0 && y0, the first string will be indented by that amount. If <0, all but the first string will be indented. It is up to the caller to ensure that the strings are sufficiently shorter than use_width to allow indenting. If alignment==ALIGN_JUSTIFIED, the last string in the array will be set left aligned. Text should be added one paragraph at a time. After setting, all strings will be truncated to use_width. */ int i; string this_line; int spaces; string blank; int indent; string indent_spaces; int indent_first; int indent_this; if (sizeof(str)==0) { return; } if (use_width==0) { /* They didn't specify a field width, so use the max of precision and the longest string */ use_width=numbers[NUM_PRECISION][0]; for (i=0;iuse_width) use_width=strlen(str[i]); } } if (numbers[NUM_INDENT]>0) { indent_first=1; indent=numbers[NUM_INDENT]; } else { indent_first=0; indent=-numbers[NUM_INDENT]; } indent_spaces=repeat_string(pad_char, indent); /* Expand result to fit all of the lines */ blank=repeat_string(pad_char, new_line_width); while ((sizeof(str)+output_line_index+line_index)>sizeof(result)) result+=({ blank }); blank=repeat_string(pad_char, final_width-use_width); for (i=0;i0 && sizeof(lines)==0) || (numbers[NUM_INDENT]<0 && sizeof(lines)!=0)) { available_width-=abs(numbers[NUM_INDENT]); } while (word_indexwidest) { widest=strlen(arg[i]); } } num_columns=numbers[NUM_WIDTH]/(widest+1); if (num_columns==0) { num_columns=1; } widths=({ }); for (i=0;i=sizeof(arg)) { this_column=arg[i*num_rows..]; } else { this_column=arg[i*num_rows..(i+1)*num_rows-1]; } add_strings(this_column, widths[i], 0, new_line_width, widths[i]+gap); } } blank=repeat_string(pad_char, numbers[NUM_WIDTH]-total_width-num_columns*gap); for (i=0;i='0' && format[posn]<='9') { number=number*10+format[posn]-'0'; posn++; } if (negative) { return -number; } else { return number; } } string sprintf(string format_string, mixed args_array...) { int i; int arg_index; int done; int expecting; result=({ "" }); format=format_string; args=args_array; posn=0; arg_index=0; err=0; output_line_index=0; while (!err && posn=strlen(format), "unexpected end of format string")) { if (format[posn+1]=='%') { while (sizeof(result)<=output_line_index) { result+=({ "" }); } result[output_line_index]+=format[posn..posn]; for (i=output_line_index+1;i=strlen(format), "unexpected end of format string")) { switch (format[posn]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': if (!error(expecting==NUM_NOTHING, "unexpected number")) { if (expecting==NUM_PRECISION) { numbers[expecting]+=({ get_number() }); } else { error(numbers[expecting]!=0, "repeated number"); numbers[expecting]=get_number(); } } expecting=NUM_NOTHING; break; case '*': if (!error(expecting==NUM_NOTHING, "unexpected '*'")) { if (!error(arg_index>=sizeof(args), "too few arguments")) { if (expecting==NUM_PRECISION) { if (typeof(args[arg_index])==T_ARRAY) { numbers[expecting]+=args[arg_index++]; } else { error(typeof(args[arg_index])!=T_INT, "expecting an integer or array argument"); numbers[expecting]+=({ args[arg_index++] }); } } else { error(typeof(args[arg_index])!=T_INT, "expecting an integer argument"); error(numbers[expecting]!=0, "repeated number"); numbers[expecting]=args[arg_index++]; } } } posn++; expecting=NUM_NOTHING; break; case '.': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); expecting=NUM_PRECISION; posn++; break; case 'i': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); expecting=NUM_INDENT; posn++; break; case 'p': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); posn++; if (!error(posn>=strlen(format), "unexpected end of format string")) { pad_char=format[posn..posn]; posn++; if (pad_char=="*") { if (!error(arg_index>=sizeof(args), "too few arguments")) { if (!error(typeof(args[arg_index])!=T_STRING, "expecting a string argument")) { pad_char=args[arg_index++]; } } } } break; case '>': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); error(alignment!=ALIGN_LEFT, "multiple alignments"); alignment=ALIGN_RIGHT; posn++; break; case '!': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); error(alignment!=ALIGN_LEFT, "multiple alignments"); alignment=ALIGN_CENTRE; posn++; break; case '|': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); error(alignment!=ALIGN_LEFT, "multiple alignments"); alignment=ALIGN_JUSTIFIED; posn++; break; case '=': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); error(type!=TYPE_NORMAL, "multiple formats"); type=TYPE_COLUMN; posn++; break; case '#': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); error(type!=TYPE_NORMAL, "multiple formats"); type=TYPE_TABLE; posn++; break; case 's': case 'a': case 'd': case 'f': error(expecting!=NUM_NOTHING && expecting!=NUM_WIDTH, "missing number"); done=1; break; default: error(1, "unknown format charcter "+format[posn..posn]); } } } if (sizeof(numbers[NUM_PRECISION])==0) { numbers[NUM_PRECISION]=({ 0 }); } if (!error(arg_index>=sizeof(args), "too few arguments")) { if (posn