Warning: Declaration of bdyssh_menu_titles::start_el(&$output, $item, $depth, $args) should be compatible with Walker_Nav_Menu::start_el(&$output, $item, $depth = 0, $args = Array, $id = 0) in /var/www/jopka/data/www/bdyssh.ru/wp-content/themes/bdyssh/functions.php on line 57
Bdyssh!
Bdyssh! // Бдыщщь!

Мне нужна твоя одежда и мотоцикл, %username%.

Группировка значений цветов в файлах SCSS / Auto color grouping in SCSS files

Main article moved here.

// process SCSS file to group same colors into variables.
// it's unfortunately refused to do in sass-convert at mainstream,
// see https://github.com/nex3/sass/issues/910

// author: jopka@kvidex.ru,  license: GPLv2
// find latest version here: http://bdyssh.ru/?p=1645

#include <stdio.h>
#include <stdlib.h>
// make code as much Pascal-like as possible while maintaining standard.
#include <iso646.h>
typedef unsigned char byte; // i am not alone!  http://www.gdargaud.net/Zips/ColorScale.zip colorscale.c line 187! typedef unsigned char  BYTE;   // 8-bit unsigned entity
#include <string.h>
#include <ctype.h> // isxdigit()

#define slength 1024    // max string length
char s[slength], ss[slength], sss[slength];
char infile[slength], tempfile[slength], outfile[slength] ;
FILE *fp_infile, *fp_outfile;

#define debug 1

int ln;
int slen;
int i, n;

int was_semicolon, comment; // boolean
int cl; // bool
int clstart, clstop;
byte byter, byteg, byteb;
float bytea;
#define max_colors 1024
//byte colors[max_colors][4]; // r,g,b
byte colors_gray[max_colors]; // grayness 0..255
byte colors_rgb[max_colors][3]; // r,g,b
 byte colors_rgba[max_colors][3]; // r,g,b
 float colors_alpha[max_colors]; // a
byte colors_qty_gray[max_colors]; // q'ty of colors, mostly for comments in resulting file
byte colors_qty_rgb[max_colors]; // q'ty of colors, mostly for comments in resulting file
byte colors_qty_rgba[max_colors]; // q'ty of colors, mostly for comments in resulting file
char cl_name_gray[max_colors][slength];
char cl_name_rgb[max_colors][slength];
char cl_name_rgba[max_colors][slength];
int num_colors_gray, num_colors_rgb, num_colors_rgba;
int total_colors_gray, total_colors_rgb, total_colors_rgba;
int cl_gray; // flag
int cl_exist;
int invert; // bool
int qty;
int skip;

int hex2decnibble(int c) {
	if ((c>='0') and (c<='9')) 			return (c-'0');
	else if ((c>='A') and (c<='F')) 	return (c-'A'+10);
	else 								return (c-'a'+10);
}

const char* usage_text = "Usage:\n"
		"$ (program) <scss_file>\n"
		"$ (program) --invert <scss_file>\n"
		"\n"
		"Description:\n"
		"In short: This program used to group same colours into scss variables.\n"
		"\n"
		"The long story: The supertask is to automatically invert all colors of given own website.\n"
		"Nowadays often css files, not html, used to define all colors.\n"
		"But they are already compiled files, not supporting currently for color variables.\n"
		"This lead to repeating same color value across file,\n"
		"and impossible to edit manually for big files.\n"
		"But surprisingly, decompiler exist to standard that has support for variables:\n"
		"it is scss file. But unfortunately, decompiler css to scss is not support for\n"
		"grouping color variables, and will never support it in future (see below).\n"
		"So we need to do it manually or using this program.\n"
		"While it was written to invert colors, as side effect it grouping same colors,\n"
		"which is useable for many other cases such as tune/change your color palette very easy.\n"
		"\n"
		"Typical scenario is:\n"
		" sudo gem install sass  (once)\n"
		" sass-convert style.css style.scss \n"
		" then use this program, then correct color values manually if no inversion was selected,\n"
		" then  sass new.style.scss:new.style.css .\n"
		"Use --invert to make eye-safe websites from tons of available styles.\n"
		"Read more here https://github.com/nex3/sass/issues/910\n"
		"\n"
		"Author:  jopka1@gmail.com,  www.bdyssh.ru\n"
		"Version 09/07/2013";

double H, S, L;
// http://www.gdargaud.net/Hack/Source/ColorScale.c
// COPYRIGHT:1995-1997 Robert Mashlan, Modified for LabWindows/CVI, 1999 Guillaume Dargaud
#define MIN3(a,b,c) ( (a)<=(b) ? (a)<=(c)?(a):(c) : (b)<=(c)?(b):(c) )
#define MAX3(a,b,c) ( (a)>=(b) ? (a)>=(c)?(a):(c) : (b)>=(c)?(b):(c) )
void RGBtoHSL(byte rr, byte gg, byte bb, float base) {
//				double *H, double *L, double *S ) {
	double delta;
	double r = (double)rr/base;
	double g = (double)gg/base;
	double b = (double)bb/base;
	double cmax = MAX3(r,g,b);
	double cmin = MIN3(r,g,b);
	L=(cmax+cmin)/2.0;
	if(cmax==cmin) S = H = 0; // it's really undefined
	else {
		if(L < 0.5)	S = (cmax-cmin)/(cmax+cmin);
		else			S = (cmax-cmin)/(2.0-cmax-cmin);
		delta = cmax - cmin;
		if (r==cmax) H = (g-b)/delta;
		else
			if(g==cmax) H = 2.0 +(b-r)/delta;
	  		else        H = 4.0+(r-g)/delta;
	  	H /= 6.0;
	  	if (H < 0.0) H += 1;
	}
}


int main(int argc, char **argv) {
	invert=0;
	if ((argc not_eq 2) && (argc not_eq 3)) {
		printf("%s\n",usage_text);
		return(0);
	}

	puts("Hi!!!!111");

	strcpy(infile, argv[1]);
	if (argc==3) {
		invert=1;
		strcpy(infile, argv[2]);
	}
	printf("Opening file '%s' for read...\n",infile);
	fp_infile=fopen(infile,"r");      //open file , read only
	if (fp_infile==NULL) {
		fprintf(stderr,"Error open file!\n");
		return 1;
	}

	sprintf(tempfile,"/tmp/temp.vcss");
	printf("Opening file '%s' for write...\n",tempfile);
	fp_outfile=fopen(tempfile,"w");
	if (fp_outfile==NULL) {
		fprintf(stderr,"Error write file!\n");
		return 1;
	}

	ln=0;
	comment=0;
	cl=0;
	num_colors_gray=0;
	num_colors_rgb=0;
	num_colors_rgba=0;
// just for display at the comment in output code	total_colors_gray=0;
	total_colors_gray=0;
	total_colors_rgb=0;
	total_colors_rgba=0;
	skip=0;
	colors_qty_gray[0]=1;
	colors_qty_rgb[0]=1;
	colors_qty_rgba[0]=1;

	while(not feof(fp_infile)) {
		s[0]=0; //to avoid EOF duplicates...
		fgets(s, sizeof s, fp_infile);
		if (s[strlen(s)-1]=='\n') {s[strlen(s)-1]='\0'; }; //strip EOL's in Windows, Mac, and Linux
		if (s[strlen(s)-1]=='\r') {s[strlen(s)-1]='\0'; };
		{
//			if (debug) printf("(line %d [%s])\n", ln, s);
			slen=strlen(s);
			was_semicolon=0; // reset each new line
			{
// processing...
//				sprintf(ss, ""); // ss - result
				ss[0]='\0';
				for (n=0; n<slen; n++) {
					cl=0;
// looking for comments to enable or disable parser
					if ((s[n]=='/') and ((n+1)<slen) and (s[n+1]=='*')) {
						comment=1;
//						if (debug) sprintf(ss, "%s!COMMENT!", ss);
					}
					if ((n>0) and (s[n-1]=='*') and (s[n]=='/')) {
						comment=0;
//						if (debug) sprintf(ss, "%s!COMMENT OFF!!!!", ss);
					}
// looking for color values:
					if (comment==0) {
// process #hhh and #hhhhhh hex colors:
						if (s[n]==':') was_semicolon=1; // now each '#' represent the color

						if ((s[n]=='#') and (was_semicolon==1)) {
							cl=0;
// we assume color walue always end by space, ';', or other non-digit, but not EOL.
							if (((n+4)<slen) and (isxdigit(s[n+1])) and (isxdigit(s[n+2])) and (isxdigit(s[n+3])) and (not (isxdigit(s[n+4])))  ) {
//								if (debug) sprintf(ss, "%s!COLOR3!", ss);
								cl=3;
//								clstart=n;
//								clstop=n+3;
							}
							if (((n+7)<slen) and (isxdigit(s[n+1])) and (isxdigit(s[n+2])) and (isxdigit(s[n+3])) \
											 and (isxdigit(s[n+4])) and (isxdigit(s[n+5])) and (isxdigit(s[n+6])) and (not (isxdigit(s[n+7]))) ) {
//								if (debug) sprintf(ss, "%s!COLOR6!", ss);
								cl=6;
//								clstart=n;
//								clstop=n+6;
							}
							if (cl>0) { // color found
								sprintf(ss, "%s$color_", ss);
//								n=n+clstop;

								if (cl==3) {
									byter=hex2decnibble(s[n+1])*17;
									byteg=hex2decnibble(s[n+2])*17;
									byteb=hex2decnibble(s[n+3])*17;
									sss[0]=s[n+1];
									sss[1]=s[n+2];
									sss[2]=s[n+3];
									sss[3]='\0';
								} else {
									byter=hex2decnibble(s[n+1])*16+hex2decnibble(s[n+2]);
									byteg=hex2decnibble(s[n+3])*16+hex2decnibble(s[n+4]);
									byteb=hex2decnibble(s[n+5])*16+hex2decnibble(s[n+6]);
									sss[0]=s[n+1];
									sss[1]=s[n+2];
									sss[2]=s[n+3];
									sss[3]=s[n+4];
									sss[4]=s[n+5];
									sss[5]=s[n+6];
									sss[6]='\0';
								}
// not work						strncpy(sss, s[n], cl); sss[cl+1]='\0';
// add treshold for not exactly equality r,g,b channels. ???
// - NO, color string names will be lost for neighbor colors.
// so do any grouping as postprocessing.
								if ( (byter==byteg) and (byteg==byteb) ) {
									cl_gray=1; // flag
								} else {
									cl_gray=0;
								}

								if (debug) printf("%d %d %d gray=%d %s\n", byter, byteg, byteb, cl_gray, sss);
// different tables for gray or coloured color
								if (cl_gray==1) {
									total_colors_gray=total_colors_gray+1;
// GRAY: check if this color new or already exist in table
									cl_exist=-1;
									for (i=0; i<num_colors_gray; i++) {
										if (colors_gray[i]==byter) {
											cl_exist=i;
											break;
										}
									}
									if (cl_exist not_eq -1) {
										if (debug) printf("found at %d\n", cl_exist);
										colors_qty_gray[cl_exist]=colors_qty_gray[cl_exist]+1;
									} else {
// GRAY: add new color into table
										colors_gray[num_colors_gray]=byter;
										strcpy(cl_name_gray[num_colors_gray], sss);
										num_colors_gray=num_colors_gray+1;
// GRAY: prepare new value
										colors_qty_gray[num_colors_gray]=1;
									}
								} else {
									total_colors_rgb=total_colors_rgb+1;
// RGB: check if this color new or already exist in table
									cl_exist=-1;
									for (i=0; i<num_colors_rgb; i++) {
										if ( (colors_rgb[i][0]==byter) and  (colors_rgb[i][1]==byteg) and (colors_rgb[i][2]==byteb) ) {
											cl_exist=i;
											break;
										}
									}
									if (cl_exist not_eq -1) {
										if (debug) printf("found at %d\n", cl_exist);
										colors_qty_rgb[cl_exist]=colors_qty_rgb[cl_exist]+1;
									} else {
// RGB: add new color into table
										colors_rgb[num_colors_rgb][0]=byter;
										colors_rgb[num_colors_rgb][1]=byteg;
										colors_rgb[num_colors_rgb][2]=byteb;
										strcpy(cl_name_rgb[num_colors_rgb], sss);
										num_colors_rgb=num_colors_rgb+1;
// RGB: prepare new value
										colors_qty_rgb[num_colors_rgb]=1;
									}

								}
							}
							if (cl>0) skip=1; else skip=0;
						} // if ((s[n]=='#') and (was_semicolon==1))
// RGBA: process rgb & rgba colors
						if ( (((n+4)<slen)) and (toupper(s[n])=='R') and (toupper(s[n+1])=='G') and (toupper(s[n+2])=='B') and (toupper(s[n+3])=='A')) {
//							sprintf(ss, "%s!RGBA!", ss);
// RGBA: find for '(', ')' brackets
							clstart=-1;
							clstop=-1;
							for (i=n+4; i<slen; i++) {
// RGBA: search for first instances of brackets
//								printf("%c",s[i]);
								if ( (clstart==-1) and ((s[i])=='(') ) clstart=i;
								if ( (clstop==-1) and ((s[i])==')') ) clstop=i;
							}
							if ( (clstart>-1) and (clstop>-1) and (clstart<clstop) ) {
							} else {
//								if (debug) printf("%d %d\n",clstart, clstop);
								printf(" ERROR: line %d, pos %d: rgb/rgba argument don't contains proper brackets.\n", ln, n);
								return EXIT_FAILURE;
							}
							clstart=clstart+1;
							if (debug) printf("RGBA: Line %d: clstart=%d clstop=%d\n", ln, clstart, clstop);
// strcpy
							sss[0]='\0';
							for (i=clstart; i<clstop; i++) {
								sss[i-clstart]=s[i];
							}
							sss[i-clstart]='\0';
//							printf("*%s*\n", sss);
// read 4 values
							qty=sscanf(sss, "%hhu, %hhu, %hhu, %f", &byter, &byteg, &byteb, &bytea);
							if (qty not_eq 4) {
								printf(" ERROR: line %d, pos %d: rgba values wrong. Qty=%d\n", ln, n, qty);
								return EXIT_FAILURE;
							}
// here color is found
							if (debug) printf("%d %d %d %4.2f *%s*\n", byter, byteg, byteb, bytea, sss);
							total_colors_rgba=total_colors_rgba+1;
							cl=1;
// check if this color new or already exist in table
							cl_exist=-1;
							for (i=0; i<num_colors_rgba; i++) {
								if ( (colors_rgba[i][0]==byter) and (colors_rgba[i][1]==byteg) and (colors_rgba[i][2]==byteb) and (colors_alpha[i]==bytea) ) {
									cl_exist=i;
									break;
								}
							}
							if (cl_exist not_eq -1) {
								if (debug) printf("found at %d\n", cl_exist);
								colors_qty_rgba[cl_exist]=colors_qty_rgba[cl_exist]+1;
// get name for substitute to output
								strcpy(sss, cl_name_rgba[cl_exist]);
							} else {
// add new color into table
								colors_rgba[num_colors_rgba][0]=byter;
								colors_rgba[num_colors_rgba][1]=byteg;
								colors_rgba[num_colors_rgba][2]=byteb;
								colors_alpha[num_colors_rgba]=bytea;
// replace non-digit chars in name
								for (i=0; i<strlen(sss); i++) if (not (isxdigit(sss[i]))) sss[i]='_';
								strcpy(cl_name_rgba[num_colors_rgba], sss);
								num_colors_rgba=num_colors_rgba+1;
// prepare new value
								colors_qty_rgba[num_colors_rgba]=1;
							}
							sprintf(ss, "%s$color_%s", ss, sss);
//							skip=strlen(sss);
							skip=clstop-n+1;
//							printf("skip=%d\n",skip);
						}

					} // if comment=0
					if (skip>0) {
//						printf("%d ",skip);
						skip=skip-1;
					} else {
						sprintf(ss, "%s%c", ss, s[n]); // ss - result
					}
				} // for
			}
			sprintf(s, "%s\n", ss);
			fputs(s, fp_outfile);
		}
		ln=ln+1;
	}

	fclose(fp_outfile);
	fclose(fp_infile);

// additional proccessing.
// add your additional stages here after main grouping of colors.

// stage 1: turn all grays into websafe, and save you from desinner's madness.
// here we preserve possibility to distinguish cologs manually later,
// if parser spread two almost same colors incorrectly,
// say 1f1f1f & 202020 fall in different sections.
// so we use double defining of gray colors:
// first we define table of web safe colors, then links to it for each main color.
#define group_gray 1	// boolean
#define step 25.5 	// good values are 51.0 (standard websafe 20% lightness step), 17.0 (gives #xxx colors from #xxxxxx), and 25.5 (10% lightness step)

	// no special processing need, just group values during output writing.

// stage 2:
// add your postprocessing...




// done processing. Now we re-open temp file and write final file.
	printf("Opening file '%s' for read...\n",tempfile);
	fp_infile=fopen(tempfile,"r");      //open file , read only
	if (fp_infile==NULL) {
		fprintf(stderr,"Error open file!\n");
		return 1;
	}

	sprintf(outfile,"new.%s",infile);
	printf("Opening file '%s' for write...\n",outfile);
	fp_outfile=fopen(outfile,"w");
	if (fp_outfile==NULL) {
		fprintf(stderr,"Error write file!\n");
		return 1;
	}

	sprintf(s, "/* This file was compiled by artificial intelligence. */\n"
			"/* Before edit, ensure that it will not be overwritten by software later. */\n"
			"\n");
	fputs(s, fp_outfile);

// write out GRAY colors, RGB colors, then RGBA colors.
int l;
float f;
	if (group_gray not_eq 0) {
		sprintf(s,"/* Gray table: step = %3.1f/255 */\n", step);
		printf("%s", s);
		fputs(s, fp_outfile);
		for (f=0; f<=255; f=f+step) {
			l=(int)(f*100.0/255.0);
			sprintf(s, "$gray%d:\tlighten(#000, %3d);\n", l, l);
			printf("%s", s);
			fputs(s, fp_outfile);
		}
	}
	sprintf(s,"/* Total grouped colors GRAY: %d, total colors GRAY was: %d */\n", num_colors_gray, total_colors_gray);
	printf("%s", s);
	fputs(s, fp_outfile);
	for (i=0; i<num_colors_gray; i++) {
		byter=colors_gray[i];
		if (invert==1) 	byter=255-byter;
		if (group_gray==0) {
			sprintf(ss, "$color_%s:\tlighten(#000, %3d);", cl_name_gray[i], (int)(byter*100.0/255.0));
		} else {
// calculate nearest color
//			l=(byter*1.0/step+0.5); // index
//			l=(int)(((int)(byter/step))+0.5)*step; // *100.0/255.0
//			l=(int)( (byter*1.0/step)+0.5)*step ; // *100.0/255.0
			l=(int) ( (int)( (byter*1.0/step)+0.5)*step *100.0/255.0 );
			sprintf(ss, "$color_%s:\t$gray%d;", cl_name_gray[i], l);
		}
		sprintf(s, "%s\t/* %s qty=%d n=%d */\n", ss, ss, colors_qty_gray[i], i);
		fputs(s, fp_outfile);
		if (debug) printf("%s", s);
	}
//	sprintf(s, "\n");
//	fputs(s, fp_outfile);

//double *clh, *cll, *cls;

	sprintf(s,"/* Total grouped colors RGB: %d, total colors RGB was: %d */\n", num_colors_rgb, total_colors_rgb);
	printf("%s", s);
	fputs(s, fp_outfile);
	for (i=0; i<num_colors_rgb; i++) {
		byter=colors_rgb[i][0];
		byteg=colors_rgb[i][1];
		byteb=colors_rgb[i][2];
		RGBtoHSL(byter, byteg, byteb, 255.0);
//printf("%d %d %d %f %f %f ", byter, byteg, byteb, H, S, L);
//		sprintf(ss, "$color_%s:\trgb(%3d, %3d, %3d);", cl_name_rgb[i], byter, byteg, byteb);
		if (invert==1)  L=1.0-L;
		sprintf(ss, "$color_%s:\thsl(%3d, %3d, %3d);", cl_name_rgb[i], (int)(H*360.0), (int)(S*100.0), (int)(L*100.0) );
		sprintf(s, "%s\t/* %s qty=%d n=%d */\n", ss, ss, colors_qty_rgb[i], i);
		fputs(s, fp_outfile);
		if (debug) printf("%s", s);
	}
//	sprintf(s, "\n");
//	fputs(s, fp_outfile);


	sprintf(s,"/* Total grouped colors RGBA: %d, total colors RGBA was: %d */\n", num_colors_rgba, total_colors_rgba);
	printf("%s", s);
	fputs(s, fp_outfile);
	for (i=0; i<num_colors_rgba; i++) {
		byter=colors_rgba[i][0];
		byteg=colors_rgba[i][1];
		byteb=colors_rgba[i][2];
		bytea=colors_alpha[i];
		RGBtoHSL(byter, byteg, byteb, 100.0);
//		sprintf(ss, "$color_%s:\trgb(%3d, %3d, %3d);", cl_name_rgb[i], byter, byteg, byteb);
		if (invert==1)  L=1.0-L;
		sprintf(ss, "$color_%s:\thsla(%3d, %3d, %3d, %4.2f);", cl_name_rgba[i], (int)(H*360.0), (int)(S*100.0), (int)(L*100.0), bytea);
//		sprintf(ss, "$color_%s:\trgba(%3d, %3d, %3d, %4.2f);", cl_name_rgba[i], byter, byteg, byteb, bytea);
		sprintf(s, "%s\t/* %s qty=%d n=%d */\n", ss, ss, colors_qty_rgba[i], i);
		fputs(s, fp_outfile);
		if (debug) printf("%s", s);
	}
//	sprintf(s, "\n");
//	fputs(s, fp_outfile);


	while(not feof(fp_infile)) {
		s[0]=0; //to avoid EOF duplicates...
		fgets(s, sizeof s, fp_infile);
		fputs(s, fp_outfile);
	}

	fclose(fp_infile);
	fclose(fp_outfile);

	puts("Bye!\n");
	return EXIT_SUCCESS;
}